6

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

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

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

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

在 C# 中,我使用 DllImport 来 pInvoke 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 000 00 00 00 02 000 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 0D 4 4 4 00 00 0D 36 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 859 69 AE 06 00 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 00 0 02 000 00 00 00 02 000 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 4 00 00 72E 6 62 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 3 BC 80 A4 59 D9 3B 3 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# 代码的外观,因为与此 Microsoft 示例中的代码相同)

4

1 回答 1

5

如果您可以发布您的 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++ 代码中删除它。

于 2009-09-18T22:27:26.497 回答