HOWTO: Export/Import Plain Text Session Key Using CryptoAPI
ID: Q228786
|
The information in this article applies to:
-
Microsoft Win32 Application Programming Interface (API), included with:
-
Microsoft Windows versions 95, 98
-
Microsoft Windows NT 4.0
-
Microsoft Windows 2000
SUMMARY
Sometimes it is convenient to export/import plain text session keys. However, the Microsoft Cryptographic Providers (Base and Enhanced) do not support this feature, for which both CryptExportKey() and CryptImportKey()require a valid key handle to encrypt and decrypt the session key, respectively. But, by using an "exponent-of-one" private key the same effect can be achieved to "encrypt" and "decrypt" the session key.
MORE INFORMATION
Since the exponent of the key is one, both the encryption and decryption do nothing to the plain text, and thus essentially leave the session key unencrypted.
Sample code below illustrates how to implement this feature:
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
//
// Data to be encrypted.
//
#define PLAIN_TEXT TEXT("This is to test exponent-of-one key")
//
// Private key with exponent of one.
//
static BYTE PrivateKeyWithExponentOfOne[] =
{
0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00,
0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0xAB, 0xEF, 0xFA, 0xC6,
0x7D, 0xE8, 0xDE, 0xFB, 0x68, 0x38, 0x09, 0x92,
0xD9, 0x42, 0x7E, 0x6B, 0x89, 0x9E, 0x21, 0xD7,
0x52, 0x1C, 0x99, 0x3C, 0x17, 0x48, 0x4E, 0x3A,
0x44, 0x02, 0xF2, 0xFA, 0x74, 0x57, 0xDA, 0xE4,
0xD3, 0xC0, 0x35, 0x67, 0xFA, 0x6E, 0xDF, 0x78,
0x4C, 0x75, 0x35, 0x1C, 0xA0, 0x74, 0x49, 0xE3,
0x20, 0x13, 0x71, 0x35, 0x65, 0xDF, 0x12, 0x20,
0xF5, 0xF5, 0xF5, 0xC1, 0xED, 0x5C, 0x91, 0x36,
0x75, 0xB0, 0xA9, 0x9C, 0x04, 0xDB, 0x0C, 0x8C,
0xBF, 0x99, 0x75, 0x13, 0x7E, 0x87, 0x80, 0x4B,
0x71, 0x94, 0xB8, 0x00, 0xA0, 0x7D, 0xB7, 0x53,
0xDD, 0x20, 0x63, 0xEE, 0xF7, 0x83, 0x41, 0xFE,
0x16, 0xA7, 0x6E, 0xDF, 0x21, 0x7D, 0x76, 0xC0,
0x85, 0xD5, 0x65, 0x7F, 0x00, 0x23, 0x57, 0x45,
0x52, 0x02, 0x9D, 0xEA, 0x69, 0xAC, 0x1F, 0xFD,
0x3F, 0x8C, 0x4A, 0xD0,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0xD5, 0xAA, 0xB1,
0xA6, 0x03, 0x18, 0x92, 0x03, 0xAA, 0x31, 0x2E,
0x48, 0x4B, 0x65, 0x20, 0x99, 0xCD, 0xC6, 0x0C,
0x15, 0x0C, 0xBF, 0x3E, 0xFF, 0x78, 0x95, 0x67,
0xB1, 0x74, 0x5B, 0x60,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
extern "C" int __cdecl _tmain (int argc, _TCHAR * argv[])
{
DWORD dwResult= 0;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hSessionKey = 0;
BYTE *pbBlob = NULL;
DWORD cbBlob;
BYTE byData[] = PLAIN_TEXT;
DWORD cbData = sizeof(byData);
DWORD dwIndex;
__try
{
//
// Acquire context for default user.
//
if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
{
dwResult = GetLastError();
if (dwResult == NTE_BAD_KEYSET)
{
if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptAcquireContext() failed.\n"), dwResult);
__leave;
}
}
else
{
dwResult = GetLastError();
__leave;
}
}
//
// Import the exponent-of-one private key.
//
if (!CryptImportKey(hProv,
PrivateKeyWithExponentOfOne,
sizeof(PrivateKeyWithExponentOfOne),
0, 0, &hKey))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptImportKey() failed.\n"), dwResult);
__leave;
}
//
// Generate exportable session key.
//
if (!CryptGenKey(hProv, CALG_RC4, CRYPT_EXPORTABLE, &hSessionKey))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptGenKey() failed.\n"), dwResult);
__leave;
}
//
// Display plain text.
//
_tprintf(TEXT("Original text = [%s]\n"), byData);
//
// Encrypt the data.
//
if (!CryptEncrypt(hSessionKey, 0, TRUE, 0, byData, &cbData, cbData))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptEncrypt() failed.\n"), dwResult);
__leave;
}
//
// Display encrypted text.
//
_tprintf(TEXT("Encrypted text = ["));
for (dwIndex = 0; dwIndex < cbData; dwIndex++)
{
_tprintf(TEXT("%c"), byData[dwIndex]);
}
_tprintf(TEXT("]\n"));
//
// Determine key blob size.
//
if (!CryptExportKey(hSessionKey, hKey, SIMPLEBLOB, 0, NULL, &cbBlob))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptExportKey() failed.\n"), dwResult);
__leave;
}
//
// Allocate memory for key blob.
//
if ((pbBlob = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbBlob)) == NULL)
{
dwResult = ERROR_NOT_ENOUGH_MEMORY;
_tprintf(TEXT("Error [0x%x]: LocalAlloc() failed.\n"), dwResult);
__leave;
}
//
// Export the session key. Resultant blob is the raw session key.
//
if (!CryptExportKey(hSessionKey, hKey, SIMPLEBLOB, 0, pbBlob, &cbBlob))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptExportKey() failed.\n"), dwResult);
__leave;
}
//
// Destroy the session key.
//
CryptDestroyKey(hSessionKey);
hSessionKey = 0;
//
// Import the session key back to decrypt the data.
//
if (!CryptImportKey(hProv, pbBlob, cbBlob, 0, 0, &hSessionKey))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptImportKey() failed.\n"), dwResult);
__leave;
}
//
// Decrypt the data.
//
if (!CryptDecrypt(hSessionKey, 0, TRUE, 0, byData, &cbData))
{
dwResult = GetLastError();
_tprintf(TEXT("Error [0x%x]: CryptDecrypt() failed.\n"), dwResult);
__leave;
}
//
// Make sure we got all the data back.
//
if (cbData != sizeof(byData) || _tcscmp((const char *) byData, PLAIN_TEXT) != 0)
{
_tprintf(TEXT("Error: Data was not decrypted correctly.\n"));
__leave;
}
//
// Display decrypted text.
//
_tprintf(TEXT("Decrypted text = [%s]\n"), byData);
}
__finally
{
//
// Release all allocated resources.
//
if (pbBlob)
LocalFree(pbBlob);
if (hSessionKey)
CryptDestroyKey(hSessionKey);
if (hKey)
CryptDestroyKey(hKey);
if (hProv)
CryptReleaseContext(hProv, 0);
}
return (int) dwResult;
}
REFERENCES
Please see MSDN online document for more information on the APIs used in the sample.
Additional query words:
CryptExportKey, CryptImportKey, Plain text session key, Private key with exponent of one, SIMPLEBLOB.
Keywords : kbAPI kbCrypt kbKernBase kbNTOS400 kbWinOS2000 kbSecurity kbWinOS95 kbWinOS98 kbfaq kbDSupport kbGrpKernBase
Version : winnt:4.0
Platform : winnt
Issue type : kbhowto