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

时间:2009-09-18 22:16:58

标签: c# c++ encryption dpapi

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

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

C#encrypt,C#decrypt(工作正常)

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

在C#中,我使用DllImport来调用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 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

在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 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

正如你所看到的那样,第一个角色是相同的,但其余角色却没有,所以如果有人知道为什么会这样,我会很感激你的帮助。

感谢。

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示例中的代码相同)

1 个答案:

答案 0 :(得分: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 ++代码中删除它。