我有一个 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 例程,看起来数据应该被正确读取和写入,但解密失败。
感谢您的帮助