This article shows how to store encrypted values into a registry entry and later retrieve them. The sample uses two classes
CEncrypt (provides a wrapper for the encryption APIs) and
CRegister(provides a wrapper for the registry operations). The registry key value encryption is useful when you want to store some sensitive data like database server username and password into the registry.The demo shows how to use these classes to write encrypted values into the registry ,as well as later retrieve these values and decrypt them to their original form.
The encryption operations are declared in
If you get problems including wincrypt.h,try the following:
#define _WIN32_WINNT 0x0400
If you don’t define
_WIN32_WINNT then the content of wincrypt.h won’t get included
Actually, it can be any value greater than 0x0400. A peep into wincrypt.h will probably help.
CryptGenKey generates keys randomly so its of no use in our case,since the encryption and decryption should be performed by the same key.We need to generate a key which is derived from a base data e.g. a string of our choice.We should use
CryptDeriveKey for this purpose.But there's some initialisation required before calling this particular function which can be dome in the done in the constructor for
The constructor code calls the following functions in the given order:
acquires an handle to the Cryptographic Service Provider (CSP )with the characteristics specified as the 4th parameter.The 3rd parameter is the name of service provider.If it is
NULL then a handle to the default provider (“Microsoft Base Cryptographic Provider” ) is provided.
The above function creates a hash object. The valid values for the 2nd parameter depends on the CSP and the characteristics specified while acquiring the context.If the value of the parameter is not compatible with CSP characteristics it will give strange results via execution.
produces a hash data based on the string passed to the constructor and the hash object created in the previous step.
This function generates the key based on the hashed data available. Again the 2nd parameter value of "CALG_RC2" is dependent on the characteristics of the CSP.
All the crypt APIs discussed above return 1 on success and 0 on error.Besides,the above code guarantees that the key generated from same string will give equivalent keys. Now let us look into the functions
int CEncrypt::Encrypt(char *msg,long orginalSize);
accepts the string to be encrypted and the orginal size of the buffer holding the string.It just calls
CryptEncrypt API.The size of the encrypted text can be larger than the lenght of "
msg" i.e., why we pass the original size of the buffer. If the buffer is not large enough to hold the encrypted text then a “
NTE_NO_MEMORY” will be generated.After the encryption the “actualSize” param contains the actual size of the encrypted text.
CEncrypt::DeCrypt just wraps up a call to
The registry is organized into keys and their values.A key in turn can have subkeys. Before retrieving a value of the key or writing a new value into it,we need to open a key.This is what is being done in the
CRegister class constructor.It accepts the name of the key which is supposed to be a descendent of the
HKEY_CURRENT_USER.It obtains a handle to the key via a call to
RegCreateKeyEx function creates the specified key. If the key already exists in the registry, the function opens it.The first param is the handle of an already open key or any of the predefined reserved HANDLE values like
Reading a Registry Value:
char *CRegister::getRegValue(char *key,DWORD *aSize);
keyName whose value is to be read.It returns a string with the key value and the size of the read data is returned in
aSize. The code for this function looks as follows:
if(RegQueryValueEx(hKey, key, 0, &dwType,
(PBYTE)NULL, &dwDataSize)==ERROR_SUCCESS && hKey!=NULL)
RegQueryValueEx(hKey, key, 0,&dwType,(PBYTE)(LPTSTR)dest,&dwDataSize);
RegQueryValueEx is used to retrieve the value from registry. The first call with the buffer set to NULL is for knowing the size of the key value,so that we can allocate adequate memory space for the registry value during the second call.
Setting a Registry Value:
void CRegister::setRegValue(char *key,char * newValue,long actualSize);
setRegValue simply sets the value of a key to a given data using the
Points to Note
RegSetValueEx which specifies type of value’s data is set to
REG_BINARY, i.e., we read and writevalues in binary form.This is done to avoid unnecessary translation of special characters while reading and writing to registry. For example suppose after encryption we get the following string “99 63 AF 00 1F F5 5E 3C” where the values in quotes represent the ascii values of characters in hexadecimal format. Notice the NULL character represented by “00”.Now if you set the dwType as
REG_SZ the string “99 63 AF 00” will only be written to registry. So information is lost and you cannot decrypt this incomplete string.For the same reason avoid using standard C-string functions on the value fetched from the registry.For example in the above case "
strlen" will give length as 3 whereas the actual size is 8.