Compiled using Visual Studio 2008 Professional. Requires linking in the crypt32 library, but this is handled within the code via a #pragma comment. This should work with all character sets as well.
//
// Encrypting and Decrypting Registry Data using Microsoft's DPAPI (Data Protection API)
// Author: JackOfAllTrades for DreamInCode.net
// Date: November 6, 2008
//
#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>
#pragma comment(lib, "crypt32.lib")
LONG WriteProtectedStringValueToRegistry(LPCTSTR subKey, LPCTSTR valueName, LPCTSTR 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_CURRENT_USER,
subKey,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&newKey,
&keyCreationResult);
if (ERROR_SUCCESS != result)
{
return result;
}
if (keyCreationResult == REG_OPENED_EXISTING_KEY)
{
_tprintf(_T("Opened existing key %sn"), subKey);
}
else
{
_tprintf(_T("Created new key %sn"), 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 = (_tcslen(value) + 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;
}
LPTSTR ReadProtectedStringValueFromRegistry(LPCTSTR subKey, LPCTSTR valueName)
{
if (!subKey || !valueName)
return NULL;
LONG result = ERROR_SUCCESS;
HKEY key;
// Open the requested key
result = RegOpenKeyEx(
HKEY_CURRENT_USER,
subKey,
0,
KEY_READ,
&key);
if (ERROR_SUCCESS != result)
return NULL;
// Read the encrypted data from the registry
// First we will determine the required buffer size for the data.
DWORD valueType = REG_BINARY;
DWORD requiredLen = 0;
result = RegQueryValueEx(
key,
valueName,
NULL,
&valueType,
NULL,
&requiredLen);
if (ERROR_SUCCESS != result)
{
RegCloseKey(key);
return NULL;
}
DATA_BLOB encryptedData, unencryptedData;
BYTE *encryptedRegistryEntry = (BYTE *)malloc(requiredLen);
result = RegQueryValueEx(
key,
valueName,
NULL,
&valueType,
encryptedRegistryEntry,
&requiredLen);
// We're done with the registry entry now.
RegCloseKey(key);
if (ERROR_SUCCESS != result)
{
free(encryptedRegistryEntry);
return NULL;
}
// OK, so we got the encrypted data, so let's decrypt it.
encryptedData.pbData = encryptedRegistryEntry;
encryptedData.cbData = requiredLen;
LPWSTR dataDescription; // Receives the description saved with data
if (!CryptUnprotectData(
&encryptedData,
&dataDescription,
NULL,
NULL,
NULL,
0,
&unencryptedData))
{
free(encryptedRegistryEntry);
return NULL;
}
// We can free the encrypted registry entry now.
free (encryptedRegistryEntry);
// And the data description string as well.
LocalFree(dataDescription);
// NOTE: Contains NULL terminator
LPTSTR unencryptedValue = (LPTSTR)malloc(unencryptedData.cbData);
_tcscpy_s(unencryptedValue, unencryptedData.cbData, (LPTSTR)unencryptedData.pbData);
// Cleanup
LocalFree(unencryptedData.pbData);
return unencryptedValue;
}
int _tmain(void)
{
LPCTSTR regSubkey = _T("SOFTWARE\DreamInCode.net\EncryptionExample");
LPCTSTR regValueName = _T("EncryptedData");
LPCTSTR regValue = _T("Do you Dream in Code???");
if (ERROR_SUCCESS != WriteProtectedStringValueToRegistry(regSubkey, regValueName, regValue))
{
_tprintf(_T("Unable to save protected datan"));
}
else
{
_tprintf(_T("Pre-encryption unencrypted value: %sn"), regValue);
LPTSTR unencryptedValue = ReadProtectedStringValueFromRegistry(regSubkey, regValueName);
if (unencryptedValue)
{
_tprintf(_T("Post-encryption unencrypted value: %sn"), unencryptedValue);
free(unencryptedValue);
}
}
return 0;
}

New Topic/Question
Reply


MultiQuote

|