0 Replies - 153 Views - Last Post: 06 November 2008 - 02:32 PM

#1 JackOfAllTrades   User is offline

  • Saucy!
  • member icon

Reputation: 6260
  • View blog
  • Posts: 24,030
  • Joined: 23-August 08

Encrypting and Decrypting Registry Data using Microsoft's DPAPI (Data

Posted 06 November 2008 - 02:32 PM

Description: This snippet demonstrates the use of Microsoft's Data Protection API to encrypt data such that only the logged-in user can decrypt it. It also demonstrates saving and retrieving binary data into a registry entry.

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;
}




Is This A Good Question/Topic? 0
  • +

Page 1 of 1