You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
833 lines
27 KiB
833 lines
27 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// File: cryptfnc.cpp
|
|
//
|
|
// Contents: This file implements the cryptfnc class that provides
|
|
// easy to use interfaces on the CryptoAPI.
|
|
//
|
|
// History: AshishS Created 12/03/96
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
|
|
|
|
#include <windows.h>
|
|
#include <cryptfnc.h>
|
|
#include <wincrypt.h>
|
|
#include <dbgtrace.h>
|
|
|
|
#ifndef CRYPT_MACHINE_KEYSET
|
|
#define CRYPT_MACHINE_KEYSET 0x00000020
|
|
#endif
|
|
|
|
|
|
// this function Generates a SessionKey using the pszPassword
|
|
// parameter
|
|
// Returns FALSE if a Fatal error occured, TRUE otherwise
|
|
BOOL CCryptFunctions::GenerateSessionKeyFromPassword(
|
|
HCRYPTKEY * phKey, // location to store the session key
|
|
TCHAR * pszPassword) // password to generate the session key from
|
|
{
|
|
DWORD dwLength;
|
|
HCRYPTHASH hHash = 0;
|
|
|
|
TraceFunctEnter("GenerateSessionKeyFromPassword");
|
|
|
|
// Init should have been successfully called before
|
|
_ASSERT(m_hProv);
|
|
|
|
// Create hash object.
|
|
if(!CryptCreateHash(m_hProv, // handle to CSP
|
|
CALG_SHA, // use SHA hash algorithm
|
|
0, // not keyed hash
|
|
0, // flags - always 0
|
|
&hHash)) // address where hash object should be created
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptCreateHash",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
// Hash password string.
|
|
dwLength = lstrlen(pszPassword) * sizeof(TCHAR);
|
|
|
|
if(!CryptHashData(hHash, // handle to hash object
|
|
(BYTE *)pszPassword, // address of data to be hashed
|
|
dwLength, // length of data
|
|
0)) // flags
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptHashData",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
// Create block cipher session key based on hash of the password.
|
|
|
|
if(!CryptDeriveKey(m_hProv, //CSP provider
|
|
CALG_RC2, // use RC2 block cipher algorithm
|
|
hHash, //handle to hash object
|
|
0, // no flags - we do not need the key to be exportable
|
|
phKey)) //address the newly created key should be copied
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptDeriveKey",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
// Destroy hash object.
|
|
_VERIFY(CryptDestroyHash(hHash));
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
|
|
cleanup:
|
|
|
|
// Destroy hash object.
|
|
if(hHash != 0)
|
|
_VERIFY(CryptDestroyHash(hHash));
|
|
TraceFunctLeave();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// This function generates a Hash using the SHA hashing
|
|
// algorithm. Four seperate buffers of data can be given to this
|
|
// function. Data of length 0 will not be used in calculation of HASH.
|
|
// Returns FALSE if a Fatal error occured, TRUE otherwise
|
|
BOOL CCryptFunctions::GenerateHash(
|
|
BYTE * pbData, // data to hash
|
|
DWORD dwDataLength, // length of data to hash
|
|
BYTE * pbData1, // another data to hash
|
|
DWORD dwData1Length, // length of above data
|
|
BYTE * pbData2, // another data to hash
|
|
DWORD dwData2Length, // length of above data
|
|
BYTE * pbData3, // another data to hash
|
|
DWORD dwData3Length, // length of above data
|
|
BYTE * pbHashBuffer, // buffer to store hash
|
|
DWORD * pdwHashBufLen)//length of buffer to store Hash
|
|
{
|
|
DWORD dwLength, dwResult;
|
|
BOOL fResult;
|
|
|
|
HCRYPTHASH hHash = 0;
|
|
|
|
TraceFunctEnter("GenerateHash");
|
|
|
|
// Init should have been successfully called before
|
|
_ASSERT(m_hProv);
|
|
|
|
dwResult = WaitForSingleObject( m_hSemaphore,// handle of object to wait for
|
|
INFINITE); // no time-out
|
|
|
|
_ASSERT(WAIT_OBJECT_0 == dwResult);
|
|
|
|
|
|
// At least one of the Data Pairs should be valid
|
|
if (! (( pbData && dwDataLength ) || ( pbData1 && dwData1Length )
|
|
|| ( pbData2 && dwData2Length ) || ( pbData3 && dwData3Length ) ) )
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "No Data to hash");
|
|
goto cleanup;
|
|
}
|
|
|
|
// now ask the user for a password and generate a session key based
|
|
// on the password. This session key will be used to encrypt the secret
|
|
// key.
|
|
// Create hash object.
|
|
if(!CryptCreateHash(m_hProv, // handle to CSP
|
|
CALG_SHA, // use SHA hash algorithm
|
|
0, // not keyed hash
|
|
0, // flags - always 0
|
|
&hHash)) // address where hash object should be created
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptCreateHash",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( pbData && dwDataLength )
|
|
{
|
|
if(!CryptHashData(hHash, // handle to hash object
|
|
pbData, // address of data to be hashed
|
|
dwDataLength, // length of data
|
|
0)) // flags
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptHashData",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if ( pbData1 && dwData1Length )
|
|
{
|
|
if(!CryptHashData(hHash, // handle to hash object
|
|
pbData1, // address of data to be hashed
|
|
dwData1Length, // length of data
|
|
0)) // flags
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptHashData",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (pbData2)
|
|
{
|
|
if(!CryptHashData(hHash, // handle to hash object
|
|
pbData2, // address of data to be hashed
|
|
dwData2Length, // length of data
|
|
0)) // flags
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptHashData",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (pbData3)
|
|
{
|
|
if(!CryptHashData(hHash, // handle to hash object
|
|
pbData3, // address of data to be hashed
|
|
dwData3Length, // length of data
|
|
0)) // flags
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptHashData",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (! CryptGetHashParam( hHash,// handle to hash object
|
|
HP_HASHVAL,// get the hash value
|
|
pbHashBuffer, // hash buffer
|
|
pdwHashBufLen, // hash buffer length
|
|
0 )) // flags
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptGetHashParam",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
// Destroy hash object.
|
|
_VERIFY(CryptDestroyHash(hHash));
|
|
|
|
_VERIFY(fResult = ReleaseSemaphore(m_hSemaphore, 1, NULL));
|
|
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
|
|
cleanup:
|
|
|
|
// Destroy hash object.
|
|
if(hHash != 0)
|
|
_VERIFY(CryptDestroyHash(hHash));
|
|
|
|
_VERIFY(fResult = ReleaseSemaphore(m_hSemaphore, 1, NULL));
|
|
|
|
TraceFunctLeave();
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
// This function must be called before any member functions of the
|
|
// class are used.
|
|
// Returns FALSE if a Fatal error occured, TRUE otherwise
|
|
// this always gets the machine keyset
|
|
BOOL CCryptFunctions::InitCrypt()
|
|
{
|
|
TraceFunctEnter("InitCrypt");
|
|
TCHAR szSemaphoreName[100];
|
|
SECURITY_ATTRIBUTES sa;
|
|
SECURITY_DESCRIPTOR sd;
|
|
BOOL fResult;
|
|
|
|
if (m_hProv)
|
|
{
|
|
DebugTrace(CRYPT_FNC_ID,"Already been inited before");
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
}
|
|
|
|
// create a Unique semaphore name for each process
|
|
wsprintf(szSemaphoreName, TEXT("%s%d"), CRYPTFNC_SEMAPHORE_NAME,
|
|
GetCurrentProcessId());
|
|
|
|
// also create a security descriptor so that everyone has access
|
|
// to the semaphore. Otherwise if the semaphore is created in a
|
|
// service running in system context, then only system can use
|
|
// this semaphore.
|
|
fResult = InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
_ASSERT(fResult);
|
|
|
|
|
|
// if the security descriptor has a NULL DACL, then this gives
|
|
// everyone access to this semaphore.
|
|
fResult = SetSecurityDescriptorDacl(&sd,
|
|
TRUE,
|
|
NULL, // NULL ACL
|
|
FALSE);
|
|
|
|
_ASSERT(fResult);
|
|
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = FALSE;
|
|
sa.lpSecurityDescriptor = & sd;
|
|
|
|
|
|
|
|
m_hSemaphore = CreateSemaphore(&sa, // pointer to security attributes
|
|
1, // initial count
|
|
1, // maximum count
|
|
szSemaphoreName);// pointer to Semaphore-object name
|
|
|
|
if ( NULL == m_hSemaphore)
|
|
{
|
|
DWORD dwError;
|
|
|
|
dwError = GetLastError();
|
|
ErrorTrace(CRYPT_FNC_ID, "CreateSemaphore failed 0x%x", dwError);
|
|
|
|
_ASSERT(0);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(!CryptAcquireContext(&m_hProv, // address to get the handle to CSP
|
|
NULL, // contianer name - use default container
|
|
NULL, // provider
|
|
PROV_RSA_FULL, // type of provider
|
|
CRYPT_VERIFYCONTEXT))
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Fatal Error 0x%x during first"
|
|
"call to CryptAcquireContext", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
#if 0 // This code is being commented out since there are problems
|
|
// getting the machine keyset from an ASP app running in the IIS
|
|
// anonymous user context. This means that we will not be able to
|
|
// do any signing or in some cases encryption. This is fine since
|
|
// we do not want to do this currently.
|
|
|
|
// Get handle to machine default provider.
|
|
if(!CryptAcquireContext(&m_hProv, // address to get the handle to CSP
|
|
NULL, // contianer name - use default container
|
|
MS_DEF_PROV, // provider
|
|
PROV_RSA_FULL, // type of provider
|
|
CRYPT_MACHINE_KEYSET))
|
|
{
|
|
DWORD dwError;
|
|
dwError = GetLastError();
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptAcquireContext",
|
|
dwError);
|
|
DebugTrace(CRYPT_FNC_ID, "Calling CryptAcquireContext again"
|
|
"to create keyset");
|
|
if (! CryptAcquireContext(&m_hProv,// handle to CSP
|
|
NULL,// contianer name - use default
|
|
MS_DEF_PROV, // provider
|
|
PROV_RSA_FULL, // type of provider
|
|
CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET) )
|
|
// create the keyset
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Fatal Error 0x%x during second"
|
|
"call to CryptAcquireContext", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
|
|
cleanup:
|
|
// Release provider handle.
|
|
if(m_hProv != 0)
|
|
{
|
|
_VERIFY(CryptReleaseContext(m_hProv, 0));
|
|
m_hProv =0 ;
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return FALSE;
|
|
}
|
|
|
|
CCryptFunctions::~CCryptFunctions()
|
|
{
|
|
TraceFunctEnter("~CCryptFunctions");
|
|
// Release provider handle.
|
|
if(m_hProv != 0)
|
|
{
|
|
_VERIFY(CryptReleaseContext(m_hProv, 0));
|
|
}
|
|
|
|
if (NULL != m_hSemaphore)
|
|
{
|
|
_VERIFY(CloseHandle(m_hSemaphore));
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
CCryptFunctions::CCryptFunctions()
|
|
{
|
|
m_hProv = 0;
|
|
m_hSemaphore = NULL;
|
|
}
|
|
|
|
// This function generates random data of length dwLength bytes. This
|
|
// data is guaranteed by CryptoAPI to be truly random.
|
|
// Returns FALSE if a Fatal error occured, TRUE otherwise
|
|
BOOL CCryptFunctions::GenerateSecretKey(
|
|
BYTE * pbData,// Buffer to store secret key
|
|
//buffer must be long enough for dwLength bits
|
|
DWORD dwLength ) // length of secret key in bytes
|
|
{
|
|
DWORD dwResult;
|
|
BOOL fResult;
|
|
|
|
// Init should have been successfully called before
|
|
_ASSERT(m_hProv);
|
|
TraceFunctEnter("GenerateSecretKey");
|
|
|
|
dwResult = WaitForSingleObject( m_hSemaphore,//handle of object to wait for
|
|
INFINITE); // no time-out
|
|
|
|
_ASSERT(WAIT_OBJECT_0 == dwResult);
|
|
|
|
|
|
// Create a random dwLength byte number for a secret.
|
|
if(!CryptGenRandom(m_hProv, // handle to CSP
|
|
dwLength , // number of bytes of
|
|
// random data to be generated
|
|
pbData )) // buffer - uninitialized
|
|
{
|
|
|
|
_VERIFY(fResult = ReleaseSemaphore(m_hSemaphore, 1, NULL));
|
|
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptGenRandom",
|
|
GetLastError());
|
|
TraceFunctLeave();
|
|
return FALSE;
|
|
}
|
|
|
|
_VERIFY(fResult = ReleaseSemaphore(m_hSemaphore, 1, NULL));
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Given a password, and data to encrypt this function generates a
|
|
// session key from the password. This session key is then used to
|
|
// encrypt the data.
|
|
|
|
// Returns FALSE if a Fatal error occured, TRUE otherwise
|
|
BOOL CCryptFunctions::EncryptDataWithPassword(
|
|
TCHAR * pszPassword, // password
|
|
BYTE * pbData, // Data to be encrypted
|
|
DWORD dwDataLength, // Length of data in bytes
|
|
BYTE * pbEncryptedData, // Encrypted secret key will be stored here
|
|
DWORD * pdwEncrytedBufferLen // Length of this buffer
|
|
)
|
|
{
|
|
DWORD dwBufferLength;
|
|
HCRYPTKEY hKey = 0;
|
|
TraceFunctEnter("EncryptDataWithPassword");
|
|
|
|
// Init should have been successfully called before
|
|
_ASSERT(m_hProv);
|
|
|
|
|
|
if (!GenerateSessionKeyFromPassword(&hKey, pszPassword))
|
|
goto cleanup;
|
|
|
|
if (dwDataLength > * pdwEncrytedBufferLen )
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Buffer not large enough");
|
|
goto cleanup;
|
|
}
|
|
|
|
// copy the data into another buffer to encrypt it
|
|
memcpy (pbEncryptedData, pbData, dwDataLength);
|
|
dwBufferLength = *pdwEncrytedBufferLen;
|
|
|
|
*pdwEncrytedBufferLen = dwDataLength;
|
|
|
|
|
|
// now encrypt the secret key using the key generated
|
|
if ( ! CryptEncrypt(hKey,
|
|
0, // no hash required
|
|
TRUE, // Final packet
|
|
0, // Flags - always 0
|
|
pbEncryptedData, // data buffer
|
|
pdwEncrytedBufferLen, // length of data
|
|
dwBufferLength ) ) // size of buffer
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptEncrypt",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// destroy session key
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
|
|
cleanup:
|
|
// destroy session key
|
|
if (hKey != 0)
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
|
|
TraceFunctLeave();
|
|
return FALSE;
|
|
}
|
|
|
|
// Given a password, and encrypted data using EncryptDataWithPassword,
|
|
// this function generates a session key from the password. This
|
|
// session key is then used to decrypt the data.
|
|
|
|
// returns
|
|
// CRYPT_FNC_NO_ERROR no error
|
|
// CRYPT_FNC_BAD_PASSWORD password bad try again
|
|
// CRYPT_FNC_INSUFFICIENT_BUFFER larger buffer is required
|
|
// *pdwEncrytedBufferLen is set to required length
|
|
// CRYPT_FNC_INIT_NOT_CALLED InitCrypt not successfully called
|
|
// CRYPT_FNC_INTERNAL_ERROR
|
|
DWORD CCryptFunctions::DecryptDataWithPassword(
|
|
TCHAR * pszPassword, // password
|
|
BYTE * pbData, // Decrypted Data will be stored here
|
|
DWORD *pdwDataBufferLength, // Length of the above buffer in bytes
|
|
BYTE * pbEncryptedData, // Encrypted data
|
|
DWORD dwEncrytedDataLen // Length of encrypted data
|
|
)
|
|
{
|
|
DWORD dwBufferLength;
|
|
HCRYPTKEY hKey = 0;
|
|
TraceFunctEnter("DecryptDataWithPassword");
|
|
DWORD dwError;
|
|
|
|
// Init should have been successfully called before
|
|
if (m_hProv== 0)
|
|
{
|
|
dwError = CRYPT_FNC_INIT_NOT_CALLED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!GenerateSessionKeyFromPassword(&hKey, pszPassword))
|
|
{
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
// check if buffer is large enough
|
|
if ( dwEncrytedDataLen > *pdwDataBufferLength )
|
|
{
|
|
dwError = CRYPT_FNC_INSUFFICIENT_BUFFER;
|
|
*pdwDataBufferLength = dwEncrytedDataLen;
|
|
goto cleanup;
|
|
}
|
|
|
|
// copy the data into another buffer to encrypt it
|
|
memcpy (pbData, pbEncryptedData, dwEncrytedDataLen);
|
|
|
|
*pdwDataBufferLength = dwEncrytedDataLen;
|
|
|
|
|
|
|
|
// now decrypt the secret key using the key generated
|
|
if ( ! CryptDecrypt(hKey,
|
|
0, // no hash required
|
|
TRUE, // Final packet
|
|
0, // Flags - always 0
|
|
pbData, // data buffer
|
|
pdwDataBufferLength )) // length of data
|
|
{
|
|
DWORD dwCryptError = GetLastError();
|
|
DebugTrace(CRYPT_FNC_ID, "Error 0x%x during CryptDecrypt",
|
|
dwCryptError);
|
|
// CryptDecrypt fails with error NTE_BAD_DATA if the password
|
|
// is incorrect. Hence we should check for this error and prompt the
|
|
// user again for the password
|
|
// Issue: if the data is garbled in transit, then the secret key
|
|
// will still be decrypted into a wrong value and the user will not
|
|
// know about it.
|
|
if ( dwCryptError == NTE_BAD_DATA )
|
|
{
|
|
dwError = CRYPT_FNC_BAD_PASSWORD;
|
|
}
|
|
else
|
|
{
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
// destroy session key
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
TraceFunctLeave();
|
|
return CRYPT_FNC_NO_ERROR;
|
|
|
|
cleanup:
|
|
// destroy session key
|
|
if (hKey != 0)
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
|
|
TraceFunctLeave();
|
|
return dwError;
|
|
}
|
|
|
|
/*
|
|
This function:
|
|
1. Generates a session key to encrypt the secret data
|
|
2. Encrypts the secret data using this session key - return this
|
|
value in the pbEncryptedData parameter
|
|
3. Encrypts the session key using the public key in the CSP -
|
|
only the private key can decrypt this value. Return the encrypted
|
|
session key in the pbEncryptedSessionKey parameter.
|
|
|
|
returns
|
|
CRYPT_FNC_NO_ERROR no error
|
|
CRYPT_FNC_INSUFFICIENT_BUFFER larger buffer is required
|
|
*pdwEncrytedBufferLen and are set to required length
|
|
CRYPT_FNC_INIT_NOT_CALLED InitCrypt not successfully called
|
|
CRYPT_FNC_INTERNAL_ERROR
|
|
|
|
*/
|
|
DWORD CCryptFunctions::EncryptDataAndExportSessionKey(
|
|
BYTE * pbData, // Secret Data
|
|
DWORD dwDataLen, // Secret Data Length
|
|
BYTE * pbEncryptedData, // Buffer to store Encrypted Data
|
|
DWORD * pdwEncrytedBufferLen, // Length of above buffer
|
|
BYTE * pbEncryptedSessionKey, // Buffer to store encrypted session key
|
|
DWORD * pdwEncrytedSessionKeyLength) // Length of above buffer
|
|
{
|
|
HCRYPTKEY hXchgKey = 0;
|
|
HCRYPTKEY hKey = 0;
|
|
DWORD dwBufferLen, dwError;
|
|
TraceFunctEnter("EncryptDataAndExportSessionKey");
|
|
|
|
// Init should have been successfully called before
|
|
if (m_hProv== 0)
|
|
{
|
|
dwError = CRYPT_FNC_INIT_NOT_CALLED;
|
|
goto cleanup;
|
|
}
|
|
|
|
// now get the public key to encrypt Secret key for storage
|
|
// Get handle to exahange key.
|
|
if(!CryptGetUserKey(m_hProv, // CSP provider
|
|
AT_KEYEXCHANGE, // we need the exchange public key
|
|
&hXchgKey))
|
|
{
|
|
DWORD dwCryptError;
|
|
dwCryptError = GetLastError();
|
|
if ( dwCryptError == NTE_NO_KEY )
|
|
{
|
|
DebugTrace(CRYPT_FNC_ID, "Error NTE_NO_KEY during"
|
|
"CryptGetUserKey");
|
|
DebugTrace(CRYPT_FNC_ID, "Calling CryptGenKey to generate key");
|
|
|
|
if (!CryptGenKey( m_hProv,// CSP provider
|
|
AT_KEYEXCHANGE, // generate the exchange
|
|
//public key
|
|
0, //no flags
|
|
&hXchgKey ) )
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptGenKey",
|
|
GetLastError());
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptGetUserKey",
|
|
GetLastError());
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
// now generate a random session key to encrypt the secret key
|
|
// Create block cipher session key.
|
|
if (!CryptGenKey(m_hProv, // CSP provider
|
|
CALG_RC2, // use RC2 block cipher algorithm
|
|
CRYPT_EXPORTABLE, // flags
|
|
&hKey)) // address of key
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptGenKey",
|
|
GetLastError());
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// Export key into a simple key blob.
|
|
if(!CryptExportKey(hKey, // key to export
|
|
hXchgKey, // our exchange public key
|
|
SIMPLEBLOB, // type of blob
|
|
0, // flags (always 0)
|
|
pbEncryptedSessionKey, // buffer to store blob
|
|
pdwEncrytedSessionKeyLength)) // length of above buffer
|
|
{
|
|
// BUGBUG check here if insufficient buffer error
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptExportKey",
|
|
GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
// check if buffer is large enough
|
|
if ( dwDataLen > *pdwEncrytedBufferLen )
|
|
{
|
|
dwError = CRYPT_FNC_INSUFFICIENT_BUFFER;
|
|
*pdwEncrytedBufferLen = dwDataLen;
|
|
goto cleanup;
|
|
}
|
|
|
|
// copy the data into another buffer to encrypt it
|
|
memcpy (pbEncryptedData, pbData, dwDataLen);
|
|
|
|
dwBufferLen = *pdwEncrytedBufferLen;
|
|
*pdwEncrytedBufferLen = dwDataLen;
|
|
|
|
|
|
// now encrypt the secret key using the key generated
|
|
if ( ! CryptEncrypt(hKey,
|
|
0, // no hash required
|
|
TRUE, // Final packet
|
|
0, // Flags - always 0
|
|
pbEncryptedData, // data buffer
|
|
pdwEncrytedBufferLen, // length of data
|
|
dwBufferLen ) ) // size of buffer
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID, "Error 0x%x during CryptEncrypt",
|
|
GetLastError());
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
_VERIFY(CryptDestroyKey(hXchgKey));
|
|
|
|
TraceFunctLeave();
|
|
return CRYPT_FNC_NO_ERROR;
|
|
|
|
cleanup:
|
|
// Destroy key exchange key handle.
|
|
if(hXchgKey != 0)
|
|
_VERIFY(CryptDestroyKey(hXchgKey));
|
|
|
|
// destroy session key
|
|
if (hKey != 0)
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
|
|
TraceFunctLeave();
|
|
return dwError;
|
|
}
|
|
|
|
|
|
/*
|
|
This function performs the reverse of EncryptDataAndExportSessionKey:
|
|
1. It imports the session key using the private key in the CSP that
|
|
was used to encrypt the secret data.
|
|
2. It decrypts the secret data using this session key - return this
|
|
value in the pbData parameter
|
|
|
|
|
|
returns
|
|
CRYPT_FNC_NO_ERROR no error
|
|
CRYPT_FNC_INSUFFICIENT_BUFFER larger buffer is required
|
|
*pdwDataLen is set to required length
|
|
CRYPT_FNC_INIT_NOT_CALLED InitCrypt not successfully called
|
|
CRYPT_FNC_INTERNAL_ERROR
|
|
|
|
*/
|
|
DWORD CCryptFunctions::ImportSessionKeyAndDecryptData(
|
|
BYTE * pbData, // Buffer to store secret Data
|
|
DWORD * pdwDataLen, // Length of Above buffer
|
|
BYTE * pbEncryptedData, // Buffer that stores Encrypted Data
|
|
DWORD dwEncrytedBufferLen, // Length of above data
|
|
BYTE * pbEncryptedSessionKey, // Buffer that stores encrypted session key
|
|
DWORD dwEncrytedSessionKeyLength) // Length of above data
|
|
{
|
|
HCRYPTKEY hKey = 0;
|
|
DWORD dwError;
|
|
|
|
TraceFunctEnter("ImportSessionKeyAndDecryptData");
|
|
|
|
// Init should have been successfully called before
|
|
if (m_hProv== 0)
|
|
{
|
|
dwError = CRYPT_FNC_INIT_NOT_CALLED;
|
|
goto cleanup;
|
|
}
|
|
|
|
// now import the key from the registry
|
|
// Import key blob into CSP.
|
|
if(!CryptImportKey( m_hProv, // CSP provider
|
|
pbEncryptedSessionKey,// buffer that stores encrypted
|
|
// session key
|
|
dwEncrytedSessionKeyLength,// length of data in
|
|
// above buffer
|
|
0, // since we have a SIMPLEBLOB and the key blob
|
|
// is encrypted with the key exchange key pair, this
|
|
// parameter is zero
|
|
0, // flags
|
|
&hKey)) // key to export to
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptImportKey",
|
|
GetLastError());
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// check if buffer is large enough
|
|
if ( dwEncrytedBufferLen > *pdwDataLen )
|
|
{
|
|
dwError = CRYPT_FNC_INSUFFICIENT_BUFFER;
|
|
*pdwDataLen = dwEncrytedBufferLen;
|
|
goto cleanup;
|
|
}
|
|
|
|
// copy the data into another buffer to encrypt it
|
|
memcpy (pbData, pbEncryptedData, dwEncrytedBufferLen);
|
|
|
|
*pdwDataLen = dwEncrytedBufferLen;
|
|
|
|
// now decrypt the secret key using the key generated
|
|
if ( ! CryptDecrypt(hKey,
|
|
0, // no hash required
|
|
TRUE, // Final packet
|
|
0, // Flags - always 0
|
|
pbData, // data buffer
|
|
pdwDataLen )) // length of data
|
|
{
|
|
ErrorTrace(CRYPT_FNC_ID,"Error 0x%x during CryptDecrypt",
|
|
GetLastError());
|
|
dwError = CRYPT_FNC_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
|
|
|
|
TraceFunctLeave();
|
|
return CRYPT_FNC_NO_ERROR;
|
|
|
|
cleanup:
|
|
|
|
// destroy session key
|
|
if (hKey != 0)
|
|
_VERIFY(CryptDestroyKey(hKey));
|
|
|
|
TraceFunctLeave();
|
|
return dwError;
|
|
|
|
}
|
|
|