为什么使用 DPAPI 加密时会得到不同的输出?

发布于 2024-08-05 08:26:31 字数 2028 浏览 2 评论 0原文

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

C++ 加密、C# 解密(运行良好)

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

C++ 加密、C# 解密,反之亦然(不起作用)

在 C# 中,我使用 DllImport 调用方法 CryptProtectData 和 CryptUnprotectData,并按照解释实现它们 这里。我知道在 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 00 02 00 00 00 00 00 03 66 00 00 A8 00 00 00 10 00 00 93 06 68 39 数据库58 FE E9 C4 1F B0 3D 7B 0A B7 48 00 00 00 00 04 80 00 00 A0 00 00 00 10 00 00 00 36 4E 84 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 69 06 00 95 29 AE 76 A7 63 E4

在 C# 中我得到:

01 00 00 00 D0 8C 9 D 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 00 02 00 00 00 00 00 03 6 6 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 00 10 00 00 00 12 54 1E 26 72 26 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 55 99 80 A4 59 D9 33 BC 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# 代码的外观< /a>,因为与此 Microsoft 示例中的相同)

I'm using DPAPI in C++ to encrypt some data that I need to store in a file. The thing is that I need to read that file from C#, so I need to be able to:

C++ encrypt, C++ decrypt (is working good)

C# encrypt, C# decrypt (is working good)

C++ encrypt, C# decrypt and vice-versa (not working)

In C# I'm using DllImport to pInvoke the methods CryptProtectData and CryptUnprotectData, and I implement them as explained here. I know that in C# I can use the methods contained in the ProtectedData class but I'm doing it in this way (using DllImport ) to make sure that both codes (c++ and c#) look and work pretty much the same.

Now the weird thing is that even if both codes looks the same I get different outputs, for example for this text:

"plain text"

in C++ I get:

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 00 02 00 00 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 10 00 00 00 36 4E 84 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 69 06 00 95 29 AE 76 A7 63 E4

and in C# I get:

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 00 02 00 00 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 00 10 00 00 00 12 54 1E 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 55 99 80 A4 59 D9 33 BC 0B 71 35 39 05 C4 BB

As you can see the first characters are the same but the rest are not, so if anyone has an idea of why this may be happening, I will appreciate the help.

Thanks.

Code in 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))

Code in C#:

(you can see how my C# code looks here, since is identical to the one in this Microsoft example )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡水深流 2024-08-12 08:26:31

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

[...]解密通常只能在
数据所在的计算机
加密

(来源: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++ 代码中将其删除。

It would help if you could post your C++ and your C# code. Perhaps there are some subtle parameter differences or something like this. For example, you should make sure that the pOptionalEntropy parameter is the same (or set it to NULL to test if this is the error source). Also, make sure to try to encrypt and decrypt on the same PC:

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

(Source: MSDN)

EDIT: Some comments on the code you posted and the C# version from MSDN (parts of it following):

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);
  [...]
}

And here's your C++ code again to have both in view:

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

The parameters don't match and I think that's the source of the differences.

The first thing is the flags. The C# code uses dwFlags != 0, your C++ code uses dwFlags = 0, so this is clearly a difference.

I'm not sure about the entropy. If you didn't pass optionalEntropy = null it is a difference, but if it is null, there's a "new byte[0]" assignment and I'm not sure about what this will create, but I think you should at least try to pass IntPtr.Zero instead of entropyBlob to CryptProtectData to match with the C++ code.

Last, but not least, your C++ code includes the trailing NUL that delimits the C string, I don't know how the encryption used here works but there are encryptions that will give you very different outputs if one byte is different (or you have one more byte like in this case), so you should either include a terminating NUL in the C# code or remove it in the C++ code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文