2

我有一个 c++ 应用程序(32 位),它将接受输入的字符串,使用名为 WriteProtectedStringValueToRegistry 的代码块对其进行加密

LONG WriteProtectedStringValueToRegistry(LPCTSTR subKey, LPCTSTR valueName, LPCTSTR      value)
{size_t len = strlen( value );

if (!subKey || !valueName)
    return ERROR_INVALID_DATA;

LONG result = 0;
DWORD keyCreationResult = 0;
HKEY newKey;

// Create a new key or open existing key.
result = RegCreateKeyEx(
    HKEY_LOCAL_MACHINE,
    subKey,
    0,
    NULL,
    0,
    KEY_ALL_ACCESS,
    NULL,
    &newKey,
    &keyCreationResult);
if (ERROR_SUCCESS != result)
{
    return result;
}

if (keyCreationResult == REG_OPENED_EXISTING_KEY)
{
  WriteLog("Opened existing key '%s'\n", subKey);
}
else
{
  WriteLog("Created new key '%s'\n", subKey);
}

DATA_BLOB unencryptedData, encryptedData;
unencryptedData.pbData = (BYTE *)value;

// Save the NULL character in the data
// We need to multiply the length of the string by the
// size of the data contained therein to support multi-
// byte character sets.
unencryptedData.cbData = (len + 1)  * sizeof(*value);
if (!CryptProtectData(
    &unencryptedData,
    L"My Encrypted Data",
    NULL,
    NULL,
    NULL,
    0,
    &encryptedData))
{
    RegCloseKey(newKey);
    return GetLastError();
}

// OK, so now we can save the data to the registry.
result = RegSetValueEx(
    newKey,
    valueName,
    0,
    REG_BINARY,
    encryptedData.pbData,
    encryptedData.cbData);

// Free the encrypted data buffer
LocalFree(encryptedData.pbData);
RegCloseKey(newKey);

return result;
}

现在 - 在另一个应用程序(c#,为任何 CPU 构建)中,我正在使用 Microsoft 的 DPAPI 类来解密从注册表读取的二进制字符串。

private void btnRead_Click(object sender, EventArgs e)
{
  try
  {
    RegistryKey rKey1 = Registry.LocalMachine;
    rKey1 = rKey1.OpenSubKey(@"SOFTWARE\XXX\XXX\Credentials", true);

    var value = (byte[])rKey1.GetValue("UserName");
    var valueAsString = BitConverter.ToString(value);

    string decrypted = DPAPI.Decrypt(EncodeTo64(valueAsString));
  }
  catch (Exception ex)
  {
    while (ex != null)
    {
      Console.WriteLine(ex.Message);
      ex = ex.InnerException;
    }
  }
}

使用测试台,我可以确认写入注册表的数据可以在 c++ 程序中加密和解密,使用不同的测试台,我可以确认加密和解密在 c# 应用程序中工作。

    string xx = DPAPI.Encrypt("Administrator");
    string yy = DPAPI.Decrypt(xx);
    // works encrypt and decrypt

    byte[] data;
    data = Convert.FromBase64String(xx);
    rKey2.SetValue("UserNamecsharp", data, RegistryValueKind.Binary);  


    byte[] value = (byte[])rKey1.GetValue("UserName");
    var valueAsString = Convert.ToBase64String(value);

    string decrypted = DPAPI.Decrypt(valueAsString);

看起来注册表中的起始值是相同的,并且通过调试器运行,它们看起来非常接近 - 直到四个 A

valueAsString
"AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAesG+C/0ymUSov+q7G6U0rAAAAAAkAAAATQB5ACAARQBuAGMAcgB5AHAAdABlAGQAIABEAGEAdABhAAAAA2YAAKgAAAAQAAAAhMQNYP/ECV0uWNQJNwR0DQAAAAAEgAAAoAAAABAAAAAusIzWvKtWfIE25su1nBkWEAAAACWxuZ2lz12ON/uOafeqdfcUAAAAs7rYAvpeXoSH191clwcFXxmIA9M=" string

xx "AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA3lfKy0QLx0KeGBAy9xuuoAAAAAACAAAAAAADZgAAwAAAABAAAAA7y9SEsVpdsVoCO78Vlq+3AAAAAASAAACgAAAAEAAAAG1Ssj5xjVqBhCm2rK9oUtIQAAAA07Fyyoq6vK2OHJ1ygG4t8RQAAACZp6TmW2EBsu7kPVlf05D+jkVC7w==" string

这是他们的注册表内容...

"用户名"=hex:01,00,00,00,d0,8c,9d,df,01,15,d1,11,8c,7a,00,c0,4f,c2,97,eb,01,\ 00 ,00,00,7a,c1,be,0b,fd,32,99,44,a8,bf,ea,bb,1b,a5,34,ac,00,00,00,00,24,00,\ 00,00,4d,00,79,00,20,00,45,00,6e,00,63,00,72,00,79,00,70,00,74,00,65,00,64, \ 00,20,00,44,00,61,00,74,00,61,00,00,00,03,66,00,00,a8,00,00,00,10,00,00,00 ,\ 84,c4,0d,60,ff,c4,09,5d,2e,58,d4,09,37,04,74,0d,00,00,00,00,04,80,00,00, a0,\ 00,00,00,10,00,00,00,2e,b0,8c,d6,bc,ab,56,7c,81,36,e6,cb,b5,9c,19,16,10 ,00,\ 00,00,25,b1,b9,9d,a5,cf,5d,8e,37,fb,8e,69,f7,aa,75,f7,14,00,00,00,b3, ba,d8,\ 02,fa,5e,5e,84,87,d7,dd,5c,97,07,05,5f,19,88,03,d3

"UserNamecsharp"=hex:01,00,00,00,d0,8c,9d,df,01,15,d1,11,8c,7a,00,c0,4f,c2,97,eb,01,\ 00 ,00,00,de,57,ca,cb,44,0b,c7,42,9e,18,10,32,f7,1b,ae,a0,00,00,00,00,02,00,\ 00,00,00,00,03,66,00,00,c0,00,00,00,10,00,00,00,3b,cb,d4,84,b1,5a,5d,b1,5a, \ 02,3b,bf,15,96,af,b7,00,00,00,00,04,80,00,00,a0,00,00,00,10,00,00,00,6d,52 ,\ b2,3e,71,8d,5a,81,84,29,b6,ac,af,68,52,d2,10,00,00,00,d3,b1,72,ca,8a,ba, bc,\ ad,8e,1c,9d,72,80,6e,2d,f1,14,00,00,00,99,a7,a4,e6,5b,61,01,b2,ee,e4,3d ,59,\ 5f,d3,90,fe,8e,45,42,ef

我一定遗漏了一些东西,使用相同的 cypt32.dll 例程,看起来数据应该被正确读取和写入,但解密失败。

感谢您的帮助

4

1 回答 1

2

乍一看,您似乎在 C++ 代码中使用 8 位 char 字符串(“string”)而不是 unicode 字符串(L“blah”或 wchar_t*)。C# 对字符串使用 Unicode。这可能就是您得到不同结果的原因。我的第一个检查是确保我将 C++ 字符串作为 unicode 传递。

祝你好运,希望这会有帮助。:)

于 2013-06-09T16:03:04.420 回答