草庐IT

c# - 为什么我在使用 DPAPI 加密时得到不同的输出?

coder 2024-02-04 原文

我在 C++ 中使用 DPAPI 来加密我需要存储在文件中的一些数据。问题是我需要从 C# 读取该文件,所以我需要能够:

C++ 加密,C++ 解密(运行良好)

C# 加密,C# 解密(运行良好)

C++ 加密,C# 解密,反之亦然(不工作)

在 C# 中,我使用 DllImport 来 pInvoke 方法 CryptProtectData 和 CryptUnprotectData,并按照说明实现它们 here .我知道在 C# 中,我可以使用 ProtectedData 类中包含的方法,但我正在以这种方式(使用 DllImport )进行操作,以确保两种代码(c++ 和 c#)的外观和工作方式几乎相同。

现在奇怪的是,即使两个代码看起来一样,我也会得到不同的输出,例如这个文本:

“纯文本”

在 C++ 中我得到:

01 00 00 00 D0 8C 9D DF 01 15 D1 11 8C 7A 00 C0 4F C2 97 EB 01 00 00 00 2E 6F 88 86 E6 16 9B 4F 9B BF 35 DA 9F C6 EC 12 00 00 00 0 0 02 02 00 00 00 0 0 02 00 00 00 03 66 00 00 A8 00 00 00 10 00 00 00 93 06 68 39 DB 58 FE E9 C4 1F B0 3D 7B 0A B7 48 00 00 00 00 04 80 00 00 A0 00 00 00 4 6 E 00 05 0D 4A 34 15 97 DC 5B 1F 6C A4 19 D9 10 00 00 00 F5 33 9F 55 49 94 26 54 2B C8 CB 70 7B FE EC 96 14 00 00 00 C5 23 DA BA C8 23 6C 0B B3 88 60 95 29 AE 76 A7 63 E4

在 C# 中我得到:

01 00 00 00 D0 8C 9D DF 01 15 D1 11 8C 7A 00 C0 4F C2 97 EB 01 00 00 00 2E 6F 88 86 E6 16 9B 4F 9B BF 35 DA 9F C6 EC 12 00 00 00 0 0 02 02 00 00 00 0 0 02 00 00 00 03 66 00 00 A8 00 00 00 10 00 00 00 34 C4 40 CD 91 EC 94 66 E5 E9 23 F7 9E 04 9C 83 00 00 00 00 04 80 00 00 A0 00 00 02 E 10 40 10 10 26 72 26 0A D1 11 1D 4D EF 13 1D B2 6F 10 00 00 00 81 9D 46 37 D1 68 5D 17 B8 23 78 48 18 ED 06 ED 14 00 00 00 E4 45 07 1C 08 59 D 4339 8 0B 71 35 39 05 C4 BB

如您所见,前几个字符相同,但其余字符不同,所以如果有人知道为什么会发生这种情况,我将不胜感激。

谢谢。

C++ 代码:


value = "plain text";
DATA_BLOB DataIn;
DATA_BLOB DataOut;

BYTE *pbDataInput =(BYTE *)(char*)value.c_str();
DWORD cbDataInput = strlen((char *)pbDataInput)+1;
DataIn.pbData = pbDataInput; 
DataIn.cbData = cbDataInput;

CryptProtectData(&DataIn, NULL, NULL, NULL, NULL, 0, &DataOut))

C# 代码:

(您可以看到我的 C# 代码看起来如何 here,因为与此 Microsoft 示例中的代码相同)

最佳答案

如果您可以发布您的 C++ 和 C# 代码,将会有所帮助。也许有一些细微的参数差异或类似的东西。例如,您应该确保 pOptionalEntropy 参数相同(或将其设置为 NULL 以测试这是否是错误源)。另外,请确保尝试在同一台 PC 上加密和解密:

[...]decryption usually can only be done on the computer where the data was encrypted

(来源:MSDN)

编辑:对您发布的代码和来自 MSDN 的 C# 版本的一些评论(部分内容如下):

public byte[] Encrypt(byte[] plainText, byte[] optionalEntropy) {
  [...]
  int bytesSize = plainText.Length;
  plainTextBlob.pbData = Marshal.AllocHGlobal(bytesSize);
  plainTextBlob.cbData = bytesSize;
  Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize);
  [...]
  dwFlags = CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
  [...]
  if(null == optionalEntropy)
  {//Allocate something
  optionalEntropy = new byte[0]; // Is copied to entropyBlob later
  }
  [...]
  retVal = CryptProtectData(ref plainTextBlob, "", ref entropyBlob,    
    IntPtr.Zero, ref prompt, dwFlags, 
    ref cipherTextBlob);
  [...]
}

这里再次显示您的 C++ 代码:

[...]
BYTE *pbDataInput =(BYTE *)(char*)value.c_str();
DWORD cbDataInput = strlen((char *)pbDataInput)+1;
[...]
CryptProtectData(&DataIn, NULL, NULL, NULL, NULL, 0, &DataOut))

参数不匹配,我认为这是差异的根源。

首先是旗帜。 C# 代码使用 dwFlags != 0,您的 C++ 代码使用 dwFlags = 0,所以这显然是不同的。

我不确定熵。如果您没有传递 optionalEntropy = null,那是不同的,但如果它为 null,则会有一个“new byte[0]”赋值,我不确定这会产生什么,但我认为您至少应该尝试一下将 IntPtr.Zero 而不是 entropyBlob 传递给 CryptProtectData 以与 C++ 代码匹配。

最后但同样重要的是,您的 C++ 代码包含分隔 C 字符串的尾随 NUL,我不知道此处使用的加密是如何工作的,但如果一个字节不同,则有一些加密会给您非常不同的输出(或者你有一个像这种情况一样的字节),所以你应该在 C# 代码中包含一个终止 NUL 或在 C++ 代码中删除它。

关于c# - 为什么我在使用 DPAPI 加密时得到不同的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1447053/

有关c# - 为什么我在使用 DPAPI 加密时得到不同的输出?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

随机推荐