CAESEncRegKey Decryption
The steps for reading an encrypted string are as follows:
- ReadString(...)
- ReadEncString(...)
- ReadData(...)
- DecryptData(...)
The ReadEncString(...) function calls ReadData(...), which returns the binary data and size of the encrypted string. It is ReadEncString(...)'s responsibility to free it. Also note that ReadData(...) opens the key using RegOpenKeyEx(...); the key is not created if missing.
Once the encrypted data is available, DecryptData(...) is called. Again, the DecryptData(...) function simply decrypts the data using AES::Decryption and CBC_Mode_ExternalCipher::Decryption objects.
LONG CAESEncRegKey::ReadEncString(CString &szValue) const
{
LONG lResult = ERROR_SUCCESS;
// Returned from the Registry through ReadData(...)
DWORD dwSize = 0;
BYTE* pcbData = NULL;
// Returned from DecryptData(...)
DWORD dwDecryptedSize = 0;
BYTE* pcbDecryptedData = NULL;
// Read From the Registry
lResult = ReadData( &pcbData, &dwSize );
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
// Undo it...
lResult = DecryptData( pcbData, dwSize, &pcbDecryptedData,
&dwDecryptedSize );
// Sanity Check
if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
// Paydirt...
szValue = reinterpret_cast<const TCHAR*>( pcbDecryptedData );
FINISHED:
// Cleanup...
if( NULL != pcbData ) { delete[] pcbData; }
if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }
return lResult;
}
Finally, when reading data, CAESEncRegKey mimics the functionality of RegQueryValueEx(...) by returning ERROR_SUCCESS or ERROR_MORE_DATA depending on the cbBuffer and cbSize arguments. See RegQueryValueEx in MSDN for a detailed explanation. Below is a sample from ReadEncBinary(...). Note that the data must be read from the Registry, and then decrypted before the buffer size can be determined.
LONG CAESEncRegKey::ReadEncBinary(BYTE* pcbData,
DWORD* dwSize) const {
...
// Read From the Registry
lResult = ReadData( &pcbRegistryData, &dwRegistrySize );
...
// Just Undo It...
lResult = DecryptData( pcbRegistryData, dwRegistrySize,
&pcbDecryptedData, &dwDecryptedSize );
...
// Emulate the RegQueryValue(...) Function
if( *dwSize < dwDecryptedSize && NULL != pcbData ) {
lResult = ERROR_MORE_DATA;
*dwSize = dwDecryptedSize;
goto FINISHED;
}
// Emulate the RegQueryValue(...) Function
if( *dwSize < dwDecryptedSize && NULL == pcbData ) {
lResult = ERROR_SUCCESS;
*dwSize = dwDecryptedSize;
goto FINISHED;
}
// Inform Caller of size of pcbData
*dwSize = dwDecryptedSize;
...
return lResult;
}
Using CAESEncRegKey
CAESEncRegKey not only provides functions for reading and writing of registry value types, it also provides mutators and accessors for changing the Registry Key object. As stated earlier, two helper structures are used to manage the AES Key and AES IV. The structures are declared and defined in aeshelper.h.
The following three examples shows object construction.
// Create an default object
CAESEncRegKey aesKey;
// Create an object setting Registry paths
CAESEncRegKey aesKey( HKEY_LOCAL_MACHINE,
_T("\\Software\\Code Guru"),
_T("Value Name") );
// Create an object setting Key and IV vectors
BYTE key[ 16 ] = { 0x00, 0x01, ... , 0x0E, 0x0F };
BYTE iv[ 16 ] = { 0x0F, 0x0E, ... , 0x01, 0x00 };
CAESEncRegKey aesKey( key, 16, iv, 16 );
If you are using the default constructor, set the five data members before invoking a WriteXXX(...) function:
CAESEncRegKey aesKey;
BYTE key[ 16 ] = { 0x00, 0x01, ... , 0x0E, 0x0F };
BYTE iv[ 16 ] = { 0x0F, 0x0E, ... , 0x01, 0x00 };
aesKey.SetKey( key, CryptoPP::AES::DEFAULT_KEYLENGTH );
aesKey.SetIV ( iv, CryptoPP::AES::BLOCKSIZE );
aesKey.Set.SetHKEY( GetHKey() );
aesKey.SetSubKey( GetSubKey() );
aesKey.SetValueName( GetStringValueName() );
aesKey.WriteString( GetStringData(), TRUE );
Reading data from the Registry is simply the reverse operation:
CAESEncRegKey aesKey;
BYTE key[ 16 ] = { 0x00, 0x01, ... , 0x0E, 0x0F };
BYTE iv[ 16 ] = { 0x0F, 0x0E, ... , 0x01, 0x00 };
aesKey.SetKey( key, CryptoPP::AES::DEFAULT_KEYLENGTH );
aesKey.SetIV ( iv, CryptoPP::AES::BLOCKSIZE );
aesKey.SetHKEY( GetHKey() );
aesKey.SetSubKey( GetSubKey() );
aesKey.SetValueName( GetStringValueName() );
CString szData;
aesKey.ReadString( szData, TRUE );
Reading multiple key values would be accomplished as follows:
CAESEncRegKey aesKey;
CString szData;
BYTE key[ 16 ] = { 0x00, 0x01, ... , 0x0E, 0x0F };
BYTE iv[ 16 ] = { 0x0F, 0x0E, ... , 0x01, 0x00 };
...
aesKey.SetValueName( _T("Value 1") );
aesKey.ReadString( szData, TRUE );
// Do something with retrieved data
aesKey.SetValueName( _T("Value 2") );
aesKey.ReadString( szData, TRUE );
// Do something with retrieved data
aesKey.SetValueName( _T("Value 3") );
aesKey.ReadString( szData, TRUE );
// Do something with retrieved data
Finally, the code from the driver program which verifies reading and writing of encrypted Binary data:
void CRegistryEncryptionDlg::OnTestBinary()
{
BYTE data[ MAX_REG_BINARY_SIZE ];
CryptoPP::AutoSeededRandomPool rng;
rng.GenerateBlock( data, MAX_REG_BINARY_SIZE );
_AESEncRegKey.SetHKEY( GetHKey() );
_AESEncRegKey.SetSubKey( GetSubKey() );
_AESEncRegKey.SetValueName( GetBinaryValueName() );
_AESEncRegKey.WriteBinary( data, MAX_REG_BINARY_SIZE, TRUE );
DWORD dwSize = MAX_REG_BINARY_SIZE;
BYTE decrypted[ MAX_REG_BINARY_SIZE ];
_AESEncRegKey.ReadBinary( decrypted, &dwSize, TRUE );
if( 0 == memcmp( data, decrypted, MAX_REG_BINARY_SIZE ) ) {
CWnd::MessageBox( _T("Binary Encryption Test Passed."),
_T("Binary Encryption Test"), MB_OK |
MB_ICONASTERISK );
} else {
CWnd::MessageBox( _T("Binary Encryption Test Failed."),
_T("Binary Encryption Test"), MB_OK |
MB_ICONERROR );
}
}
Crypto++ and VisualC++ Compatibility
When linking cryptlib.lib (or cryptlibd.lib) to a MFC project, the following may ease the use of the Crypto++ library. Place the following in stdafx.h:
#ifdef _UNICODE
# pragma comment( linker, "/ENTRY:wWinMainCRTStartup")
#endif
#pragma warning(disable: 4786)
#pragma warning(disable: 4231)
// Crypto++ Library
#ifdef _DEBUG
# pragma comment ( lib, "cryptlibd" )
#else
# pragma comment ( lib, "cryptlib" )
#endif
// Debug Libraries
// #pragma comment( linker, "/NODEFAULTLIB:msvcprtd.lib" )
// #pragma comment( linker, "/NODEFAULTLIB:libcmtd.lib" )
// #pragma comment( linker, "/NODEFAULTLIB:msvcrtd.lib" )
// #pragma comment( linker, "/NODEFAULTLIB:libcd.lib" )
// Release Libraries
// #pragma comment( linker, "/NODEFAULTLIB:msvcprt.lib" )
// #pragma comment( linker, "/NODEFAULTLIB:libcmt.lib" )
// #pragma comment( linker, "/NODEFAULTLIB:msvcrt.lib" )
// #pragma comment( linker, "/NODEFAULTLIB:libc.lib" )
If LNK1104 errors are encountered, re-run Visual Studio setup and install the MFC Unicode libraries.
[link1104.gif]
[msvs_unicode.gif]
If one encounters LNK2005 'Default Library' errors, verify the MFC project is:
- Using MFC as a Static Library
- Using Multithreaded MFC Libraries
If that fails, uncomment the appropriate #pragma statement in stdafx.h. See Carl Daniel's comment on the error from Google's Usenet archive.
History
- 11/14/2006: Updated Crypto++ Link
- 11/14/2006: Updated Article Graphics
- 10/10/2005: Initial Release
Comments
There are no comments yet. Be the first to comment!