Windows2003-3790/termsrv/newclient/core/capienc.cpp
2020-09-30 16:53:55 +02:00

1011 lines
30 KiB
C++

/****************************************************************************/
/* capienc.cpp */
/* */
/* FIPS encrpt/decrypt */
/* */
/* Copyright (C) 2002-2004 Microsoft Corporation */
/****************************************************************************/
#include <adcg.h>
extern "C" {
#define TRC_GROUP TRC_GROUP_CORE
#define TRC_FILE "capienc"
#include <atrcapi.h>
}
#include "capienc.h"
#include "sl.h"
#define TERMSRV_NAME L"terminal_server_client"
const BYTE DESParityTable[] = {0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03,
0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04};
// IV for all block ciphers
BYTE rgbIV[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
//
// Name: PrintData
//
// Purpose: Print out the data in debugger
//
// Returns: No
//
// Params: IN pKeyData: point to the data to be printed
// IN cbSize: the size of the key
void PrintData(BYTE *pKeyData, DWORD cbSize)
{
DWORD dwIndex;
TCHAR Buffer[128];
for( dwIndex = 0; dwIndex<cbSize; dwIndex++ ) {
StringCchPrintf(Buffer, 128, TEXT("0x%x "), pKeyData[dwIndex]);
OutputDebugString(Buffer);
if( dwIndex > 0 && (dwIndex+1) % 8 == 0 )
OutputDebugString((TEXT("\n")));
}
}
//
// Name: Is_WinXP_or_Later
//
// Purpose: Tell if the OS is WinXP or later
//
// Returns: TRUE if it's WinXP or later
//
// Params: No
BOOL Is_WinXP_or_Later ()
{
OSVERSIONINFO osvi;
BOOL bIsWinXPorLater = FALSE;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&osvi)) {
bIsWinXPorLater = ((osvi.dwMajorVersion >= 5) && (osvi.dwMinorVersion >= 1));
}
return bIsWinXPorLater;
}
//
// Name: Mydesparityonkey
//
// Purpose: Set the parity on the DES key to be odd
//
// Returns: No
//
// Params: IN/OUT pbKey: point to the key
// IN cbKey: the size of the key
void Mydesparityonkey(
BYTE *pbKey,
DWORD cbKey
)
{
DWORD i;
for (i=0;i<cbKey;i++)
{
if (!((DESParityTable[pbKey[i]>>4] + DESParityTable[pbKey[i]&0x0F]) % 2))
pbKey[i] = pbKey[i] ^ 0x01;
}
}
//
// Name: Expandkey
//
// Purpose: Expand a 21-byte 3DES key to a 24-byte 3DES key (including parity bit)
// by inserting a parity bit after every 7 bits in the 21-byte DES
//
// Returns: No
//
// Params: IN/OUT pbKey: point to the key
//
#define PARITY_UNIT 7
void Expandkey(
BYTE *pbKey
)
{
BYTE pbTemp[DES3_KEYLEN];
DWORD i, dwCount;
UINT16 shortTemp;
BYTE *pbIn, *pbOut;
memcpy(pbTemp, pbKey, sizeof(pbTemp));
dwCount = (DES3_KEYLEN * 8) / PARITY_UNIT;
pbOut = pbKey;
for (i=0; i<dwCount; i++) {
pbIn = ((pbTemp + (PARITY_UNIT * i) / 8));
//shortTemp = *(pbIn + 1);
shortTemp = *pbIn + (((UINT16)*(pbIn + 1)) << 8);
shortTemp = shortTemp >> ((PARITY_UNIT * i) % 8);
//shortTemp = (*(unsigned short *)((pbTemp + (PARITY_UNIT * i) / 8))) >> ((PARITY_UNIT * i) % 8);
*pbOut = (BYTE)(shortTemp & 0x7F);
pbOut++;
}
}
// Name: HashData
//
// Purpose: Hash the data using SHA.
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiFunctionTable: CAPI function table
// IN hProv: Handle of the cript provider
// IN pbData: point to the data to be hashed
// IN dwDataLen: the size of the data to be hashed
// OUT phHash: point to the hash
BOOL HashData(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen, HCRYPTHASH* phHash)
{
BOOL rc = FALSE;
DC_BEGIN_FN("HashData");
//
// Create a hash object.
//
if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_SHA1, 0, 0, phHash)) {
TRC_ERR((TB, _T("Error %x during CryptCreateHash!\n"), GetLastError()));
goto done;
}
//
// Hash in the data.
//
if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
goto done;
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: HashDataEx
//
// Purpose: Hash 2 set of data using SHA.
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiFunctionTable: CAPI function table
// IN hProv: Handle of the cript provider
// IN pbData: point to the data to be hashed
// IN dwDataLen: the size of the data to be hashed
// IN pbData2: point to the data to be hashed
// IN dwDataLen2: the size of the data to be hashed
// OUT phHash: point to the hash
BOOL HashDataEx(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen,
PBYTE pbData2, DWORD dwDataLen2, HCRYPTHASH* phHash)
{
BOOL rc = FALSE;
DC_BEGIN_FN("HashDataEx");
//
// Create a hash object.
//
if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_SHA1, 0, 0, phHash)) {
printf("Error %x during CryptCreateHash!\n", GetLastError());
goto done;
}
//
// Hash in the data.
//
if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
printf("Error %x during CryptHashData!\n", GetLastError());
goto done;
}
if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData2, dwDataLen2, 0)) {
printf("Error %x during CryptHashData!\n", GetLastError());
goto done;
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: HmacHashData
//
// Purpose: Hash the data using HmacSHA.
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiFunctionTable: CAPI function table
// IN hProv: Handle of the cript provider
// IN pbData: point to the data to be hashed
// IN dwDataLen: the size of the data to be hashed
// IN hKey: handle to the key
// OUT phHash: point to the hash
BOOL HmacHashData(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen,
HCRYPTKEY hKey, HCRYPTHASH* phHash)
{
BOOL rc = FALSE;
BYTE bmacinfo[sizeof(HMAC_INFO)];
HMAC_INFO* pmac;
memset(bmacinfo, 0, sizeof(bmacinfo));
pmac = (HMAC_INFO*)bmacinfo;
pmac->HashAlgid = CALG_SHA1;
DC_BEGIN_FN("HmacHashData");
//
// Create a hash object.
//
if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_HMAC, hKey, 0, phHash)) {
TRC_ERR((TB, _T("Error %x during CryptCreateHash!\n"), GetLastError()));
goto done;
}
rc = pCapiFunctionTable->pfnCryptSetHashParam(*phHash, HP_HMAC_INFO, bmacinfo, 0);
//
// Hash in the data.
//
if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
goto done;
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: HmacHashDataEx
//
// Purpose: Hash 2 set of data using HmacSHA.
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiFunctionTable: CAPI function table
// IN hProv: Handle of the cript provider
// IN pbData: point to the data to be hashed
// IN dwDataLen: the size of the data to be hashed
// IN pbData2: point to the data to be hashed
// IN dwDataLen2: the size of the data to be hashed
// IN hKey: handle to the key
// OUT phHash: point to the hash
BOOL HmacHashDataEx(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen,
PBYTE pbData2, DWORD dwDataLen2, HCRYPTKEY hKey, HCRYPTHASH* phHash)
{
BOOL rc = FALSE;
BYTE bmacinfo[sizeof(HMAC_INFO)];
HMAC_INFO* pmac;
memset(bmacinfo, 0, sizeof(bmacinfo));
pmac = (HMAC_INFO*)bmacinfo;
pmac->HashAlgid = CALG_SHA1;
DC_BEGIN_FN("HmacHashDataEx");
//
// Create a hash object.
//
if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_HMAC, hKey, 0, phHash)) {
TRC_ERR((TB, _T("Error %x during CryptCreateHash!\n"), GetLastError()));
goto done;
}
rc = pCapiFunctionTable->pfnCryptSetHashParam(*phHash, HP_HMAC_INFO, bmacinfo, 0);
//
// Hash in the data.
//
if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
goto done;
}
if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData2, dwDataLen2, 0)) {
TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
goto done;
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: DumpHashes
//
// Purpose: Get the hash bits from hash handle
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiFunctionTable: CAPI function table
// IN phHash: point to hash handle
// OUT pbBytes: point data buffer to get hash
// IN dwTotal: len of the data buffer
BOOL DumpHashes(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTHASH* phHash, PBYTE pbBytes, DWORD dwTotal)
{
BOOL rc = FALSE;
DC_BEGIN_FN("DumpHashes");
if (!pCapiFunctionTable->pfnCryptGetHashParam(*phHash, HP_HASHVAL, pbBytes, &dwTotal , 0)) {
TRC_ERR((TB, _T("Error %x during CryptGetHashParam!\n"), GetLastError()));
goto done;
}
//
//destroy the hash, we don't need it anymore
//
if(*phHash) {
pCapiFunctionTable->pfnCryptDestroyHash(*phHash);
*phHash = 0;
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: TSCAPI_Init
//
// Purpose: Initialize the CAPI function table.
//
// Returns: TRUE - succeeded
// FALSE - failed
//
// Params: IN pCapiData: CAPI data
BOOL TSCAPI_Init(PCAPIData pCapiData)
{
BOOL rc = FALSE;
// FIPS is only available on WinXP and later
if (!Is_WinXP_or_Later()) {
goto done;
}
pCapiData->hAdvapi32 = LoadLibrary(L"advapi32.dll");
if (pCapiData->hAdvapi32 == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptAcquireContext = (CRYPTACQUIRECONTEXT *)GetProcAddress(
pCapiData->hAdvapi32, "CryptAcquireContextW")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptReleaseContext = (CRYPTRELEASECONTEXT *)GetProcAddress(
pCapiData->hAdvapi32, "CryptReleaseContext")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptGenRandom = (CRYPTGENRANDOM *)GetProcAddress(
pCapiData->hAdvapi32, "CryptGenRandom")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptEncrypt = (CRYPTENCRYPT *)GetProcAddress(
pCapiData->hAdvapi32, "CryptEncrypt")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptDecrypt = (CRYPTDECRYPT *)GetProcAddress(
pCapiData->hAdvapi32, "CryptDecrypt")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptImportKey = (CRYPTIMPORTKEY *)GetProcAddress(
pCapiData->hAdvapi32, "CryptImportKey")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptSetKeyParam = (CRYPTSETKEYPARAM *)GetProcAddress(
pCapiData->hAdvapi32, "CryptSetKeyParam")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptDestroyKey = (CRYPTDESTROYKEY *)GetProcAddress(
pCapiData->hAdvapi32, "CryptDestroyKey")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptCreateHash = (CRYPTCREATEHASH *)GetProcAddress(
pCapiData->hAdvapi32, "CryptCreateHash")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptHashData = (CRYPTHASHDATA *)GetProcAddress(
pCapiData->hAdvapi32, "CryptHashData")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptSetHashParam = (CRYPTSETHASHPARAM *)GetProcAddress(
pCapiData->hAdvapi32, "CryptSetHashParam")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptGetHashParam = (CRYPTGETHASHPARAM *)GetProcAddress(
pCapiData->hAdvapi32, "CryptGetHashParam")) == NULL) {
goto done;
}
if ((pCapiData->CapiFunctionTable.pfnCryptDestroyHash = (CRYPTDESTROYHASH *)GetProcAddress(
pCapiData->hAdvapi32, "CryptDestroyHash")) == NULL) {
goto done;
}
rc = TRUE;
done:
return rc;
}
// Name: TSCAPI_Enable
//
// Purpose: Some CAPI initialization
//
// Returns: TRUE - succeeded
// FALSE - failed
//
// Params: IN pCapiData: CAPI data
BOOL TSCAPI_Enable(PCAPIData pCapiData)
{
BOOL rc = FALSE;
DWORD Error;
DWORD dwExtraFlags = 0;
HRESULT hr;
DC_BEGIN_FN("TSCAPI_Enable");
// Get handle to the default provider.
if(!pCapiData->CapiFunctionTable.pfnCryptAcquireContext(&(pCapiData->hProv),
TERMSRV_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, dwExtraFlags)) {
// Could not acquire a crypt context, get the reason of failure
Error = GetLastError();
hr = HRESULT_FROM_WIN32(Error);
if (hr == NTE_BAD_KEYSET) {
//
//create a new keyset
//
if(!pCapiData->CapiFunctionTable.pfnCryptAcquireContext(&(pCapiData->hProv), TERMSRV_NAME,
MS_ENHANCED_PROV, PROV_RSA_FULL, dwExtraFlags | CRYPT_NEWKEYSET)) {
Error = GetLastError();
TRC_ERR((TB, _T("Error %x during CryptAcquireContext!\n"), GetLastError()));
goto done;
}
}
else {
goto done;
}
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: TSCAPI_Term
//
// Purpose: Terminate the CAPI .
//
// Returns: TRUE if succeeded
//
//
// Params: IN pCapiData: CAPI data
BOOL TSCAPI_Term(PCAPIData pCapiData)
{
BOOL rc = TRUE;
DC_BEGIN_FN("TSCAPI_Enable");
if (pCapiData->hEncKey) {
rc = pCapiData->CapiFunctionTable.pfnCryptDestroyKey(pCapiData->hEncKey);
pCapiData->hEncKey = NULL;
}
if (pCapiData->hDecKey) {
rc = pCapiData->CapiFunctionTable.pfnCryptDestroyKey(pCapiData->hDecKey);
pCapiData->hDecKey = NULL;
}
if (pCapiData->hProv) {
rc = pCapiData->CapiFunctionTable.pfnCryptReleaseContext(pCapiData->hProv, 0);
pCapiData->hProv = NULL;
}
DC_END_FN();
return rc;
}
// Name: TSCAPI_GenerateRandomNumber
//
// Purpose: Generates random number using CAPI in user mode
//
// Returns: TRUE if succeeded
//
//
// Params: IN pCapiData: CAPI data
// OUT pbRandomBits: pointer to a buffer where a random key is returned.
// IN cbLen: length of the random key required.
BOOL TSCAPI_GenerateRandomNumber(
PCAPIData pCapiData,
LPBYTE pbRandomBits,
DWORD cbLen)
{
BOOL rc = FALSE;
DC_BEGIN_FN("TSCAPI_GenerateRandomNumber");
if (pCapiData->CapiFunctionTable.pfnCryptGenRandom(pCapiData->hProv, cbLen, pbRandomBits)) {
rc = TRUE;
}
done:
DC_END_FN();
return rc;
}
// Name: ImportKey
//
// Purpose: Import the key in bits to crypt provider
//
// Returns: TRUE if succeeded
//
//
// Params: IN pCapiData: CAPI data
// IN hProv: handle to the crypt provider
// IN Algid: Algorithm identifier
// IN pbKey: point to the buffer contain the key bits
// IN dwKeyLen: length of the key.
// IN dwFlags: dwFlags used in CryptImportKey
// OUT phKey: point to the key handle
BOOL ImportKey(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, ALG_ID Algid, PBYTE pbKey, DWORD dwKeyLen, DWORD dwFlags, HCRYPTKEY* phKey)
{
BOOL rc = FALSE;
PBYTE pbData = NULL;
DWORD cbLen = 0;
DWORD Error;
//
//create blob header first
//
BLOBHEADER blobHead;
blobHead.bType = PLAINTEXTKEYBLOB;
blobHead.bVersion = 2;
blobHead.reserved = 0;
blobHead.aiKeyAlg = Algid;
DC_BEGIN_FN("ImportKey");
//
//calculate the length
//
cbLen = sizeof(blobHead) + sizeof(dwKeyLen) + dwKeyLen;
pbData = (PBYTE)LocalAlloc(LPTR, cbLen);
if(NULL == pbData) {
TRC_ERR((TB, _T("Out of memory\n")));
goto done;
}
//
//copy data. First data must be header, then the size of the key, then the key
//
memcpy( pbData, &blobHead, sizeof(blobHead));
memcpy( pbData + sizeof(blobHead), &dwKeyLen, sizeof(dwKeyLen));
memcpy( pbData + sizeof(blobHead) + sizeof(dwKeyLen), pbKey, dwKeyLen);
if( !pCapiFunctionTable->pfnCryptImportKey( hProv, pbData, cbLen, 0, dwFlags, phKey)) {
Error = GetLastError();
TRC_ERR((TB, _T("Failed to import plaint text key Error = 0x%x\n"), Error));
*phKey = 0;
goto done;
}
rc = TRUE;
done:
DC_END_FN();
if(pbData) {
LocalFree(pbData);
}
return rc;
}
// Name: TSCAPI_DeriveKey
//
// Purpose: Derive the key from the hash.
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiFunctionTable: CAPI function table
// IN hProv: crypt provider handle
// OUT phKey: point to key handle
// IN rgbSHABase: base data used to derive the key
// IN cbSHABase: size of the base data
// OUT pbKey: point to the derived DESkey
// OUT pdwKeyLen: point to the key length
BOOL TSCAPI_DeriveKey(
PCAPI_FUNCTION_TABLE pCapiFunctionTable,
HCRYPTPROV hProv,
HCRYPTKEY *phKey,
BYTE *rgbSHABase,
DWORD cbSHABase,
BYTE *pbKey,
DWORD *pdwKeyLen)
{
BOOL rc = FALSE;
BOOL fRet = FALSE;
BYTE rgb3DESKey[MAX_FIPS_SESSION_KEY_SIZE];
DC_BEGIN_FN("TSCAPI_DeriveKey");
//
//Generate the key as follows
//1. Hash the secret. Call the result H1 (rgbSHABase in our case)
//2. Use 1st 21 bytes of [H1|H1] as the 3DES key
//3. Expand the 21-byte 3DES key to a 24-byte 3DES key (including parity bit), which
// will be used by CryptAPI
//4. Set the parity on the 3DES key to be odd
//
//Step 2 - [H1|H1]
//
memcpy(rgb3DESKey, rgbSHABase, cbSHABase);
memcpy(rgb3DESKey + cbSHABase, rgbSHABase, DES3_KEYLEN - cbSHABase);
//
//Step 3 - Expand the key
//
Expandkey(rgb3DESKey);
//
//Step 4 - Set parity
//
Mydesparityonkey(rgb3DESKey, sizeof(rgb3DESKey));
//
//import the key as PLAINTEXT into the csp
//
rc = ImportKey(pCapiFunctionTable, hProv, CALG_3DES, rgb3DESKey, sizeof(rgb3DESKey), 0, phKey);
if (!rc) {
goto done;
}
//give the key to the caller
//
memcpy(pbKey, rgb3DESKey, sizeof(rgb3DESKey));
*pdwKeyLen = sizeof(rgb3DESKey);
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: TSCAPI_MakeSessionKeys
//
// Purpose: Make the key from client/server random numbers
//
// Returns: TRUE if succeeded
//
// Params: IN pCapiData: CAPI Data
// IN pKeyPair: Randow numbers used to generate key
// IN pEnumMethod: To generate Encrypt or Decrypt key, If NULL, both keys
BOOL TSCAPI_MakeSessionKeys(
PCAPIData pCapiData,
RANDOM_KEYS_PAIR *pKeyPair,
CryptMethod *pEnumMethod)
{
BOOL rc = FALSE;
HCRYPTHASH hHash;
DWORD dwKeyLen;
BYTE rgbSHABase1[A_SHA_DIGEST_LEN];
BYTE rgbSHABase2[A_SHA_DIGEST_LEN];
DC_BEGIN_FN("TSCAPI_MakeSessionKeys");
memset(rgbSHABase1, 0, sizeof(rgbSHABase1));
memset(rgbSHABase2, 0, sizeof(rgbSHABase2));
//
// Client Encrypt/Server Decrypt key
//
if ((pEnumMethod == NULL) ||
(*pEnumMethod == Encrypt)) {
if (!pCapiData->CapiFunctionTable.pfnCryptCreateHash(pCapiData->hProv, CALG_SHA1, 0, 0, &hHash)) {
TRC_ERR((TB, _T("CryptCreateHash failed with %u"), GetLastError()));
goto done;
}
if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->clientRandom + RANDOM_KEY_LENGTH/2, RANDOM_KEY_LENGTH/2, 0)) {
TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
goto done;
}
if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->serverRandom + RANDOM_KEY_LENGTH/2, RANDOM_KEY_LENGTH/2, 0)) {
TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
goto done;
}
if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, rgbSHABase1, sizeof(rgbSHABase1))) {
goto done;
}
dwKeyLen = sizeof(pCapiData->bEncKey);
if (!TSCAPI_DeriveKey(&(pCapiData->CapiFunctionTable), pCapiData->hProv, &(pCapiData->hEncKey), rgbSHABase1,
sizeof(rgbSHABase1), pCapiData->bEncKey, &dwKeyLen)) {
goto done;
}
//
//set the IV
//
if(!pCapiData->CapiFunctionTable.pfnCryptSetKeyParam(pCapiData->hEncKey, KP_IV, rgbIV, 0 )) {
TRC_ERR((TB, _T("Error %x during CryptSetKeyParam!\n"), GetLastError()));
goto done;
}
}
//
// Server Encrypt/Client Decrypt key
//
if ((pEnumMethod == NULL) ||
(*pEnumMethod == Decrypt)) {
if (!pCapiData->CapiFunctionTable.pfnCryptCreateHash(pCapiData->hProv, CALG_SHA1, 0, 0, &hHash)) {
TRC_ERR((TB, _T("CryptCreateHash failed with %u"), GetLastError()));
goto done;
}
if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->clientRandom, RANDOM_KEY_LENGTH/2, 0)) {
TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
goto done;
}
if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->serverRandom, RANDOM_KEY_LENGTH/2, 0)) {
TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
goto done;
}
if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, rgbSHABase2, sizeof(rgbSHABase2))) {
goto done;
}
dwKeyLen = sizeof(pCapiData->bDecKey);
if (!TSCAPI_DeriveKey(&(pCapiData->CapiFunctionTable), pCapiData->hProv, &(pCapiData->hDecKey), rgbSHABase2,
sizeof(rgbSHABase2), pCapiData->bDecKey, &dwKeyLen)) {
goto done;
}
//
//set the IV
//
if(!pCapiData->CapiFunctionTable.pfnCryptSetKeyParam(pCapiData->hDecKey, KP_IV, rgbIV, 0 )) {
TRC_ERR((TB, _T("Error %x during CryptSetKeyParam!\n"), GetLastError()));
goto done;
}
}
//
// Get the signing key
// The signing key is SHA(rgbSHABase2|rgbSHABase1)
//
if (pEnumMethod == NULL) {
if (!HashDataEx(&(pCapiData->CapiFunctionTable), pCapiData->hProv, rgbSHABase2, sizeof(rgbSHABase2),
rgbSHABase1, sizeof(rgbSHABase1), &hHash)) {
goto done;
}
if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, pCapiData->bSignKey, sizeof(pCapiData->bSignKey))) {
goto done;
}
rc = ImportKey(&(pCapiData->CapiFunctionTable), pCapiData->hProv, CALG_RC2, pCapiData->bSignKey, sizeof(pCapiData->bSignKey), CRYPT_IPSEC_HMAC_KEY, &(pCapiData->hSignKey));
if (!rc) {
goto done;
}
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: TSCAPI_AdjustDataLen
//
// Purpose: In Block encryption mode, adjust the data len to multiple of blocks
//
// Returns: Adjusted data length
//
// Params: IN dataLen: Data length needed to be encrypted
DCUINT TSCAPI_AdjustDataLen(DCUINT dataLen)
{
return (dataLen - dataLen % FIPS_BLOCK_LEN + FIPS_BLOCK_LEN);
}
// Name: TSCAPI_EncryptData
//
// Purpose: Encrypt the data and compute the signature
//
// Returns: No
//
// Params: IN pCapiData: CAPI Data
// IN/OUT pbData: pointer to the data buffer being encrypted, encrypted data is
// returned in the same buffer.
// IN/OUT pdwDataLen: data length to be encrypted, and returns encrypted data length
// IN dwPadLen: padding length in the data buffer
// OUT pbSignature: pointer to a signature buffer where the data signature is returned.
// IN dwEncryptionCount: running counter of all encryptions
BOOL TSCAPI_EncryptData(
PCAPIData pCapiData,
LPBYTE pbData,
DWORD *pdwDataLen,
DWORD dwBufLen,
LPBYTE pbSignature,
DWORD dwEncryptionCount)
{
BOOL rc = FALSE;
DWORD Error;
HCRYPTHASH hHash;
BYTE rgbSHA[A_SHA_DIGEST_LEN];
BYTE pbHmac[A_SHA_DIGEST_LEN];
DWORD dwTemp = dwBufLen;
DC_BEGIN_FN("TSCAPI_EncryptData");
// Compute signature
if (!HmacHashDataEx(&(pCapiData->CapiFunctionTable), pCapiData->hProv, pbData, *pdwDataLen, (BYTE *)&dwEncryptionCount,
sizeof(dwEncryptionCount), pCapiData->hSignKey, &hHash)) {
goto done;
}
if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, pbHmac, sizeof(pbHmac))) {
goto done;
}
// Take the 1st 8 bytes of Hmac as signature
memcpy(pbSignature, pbHmac, MAX_SIGN_SIZE);
rc = pCapiData->CapiFunctionTable.pfnCryptEncrypt(pCapiData->hEncKey,
NULL, //Hash
FALSE, //Final
0,
pbData,
&dwTemp,
dwBufLen);
if (!rc) {
TRC_ERR((TB, _T("Error %x during CryptEncrypt!\n"), GetLastError()));
goto done;
}
rc = TRUE;
done:
DC_END_FN();
return rc;
}
// Name: TSCAPI_DecryptData
//
// Purpose: Decrypt the data and compare the signature
//
// Returns: TRUE if successfully decrypted the data
//
// Params: IN PCAPIData: CAPI Data
// IN/OUT pbData: pointer to the data buffer being decrypted, decrypted data is
// returned in the same buffer.
// IN dwDataLen: data length to be decrypted
// IN dwPadLen: padding length in the data buffer
// IN pbSignature: pointer to a signature buffer
// IN dwDecryptionCount: running counter of all encryptions
BOOL TSCAPI_DecryptData(
PCAPIData pCapiData,
LPBYTE pbData,
DWORD dwDataLen,
DWORD dwPadLen,
LPBYTE pbSignature,
DWORD dwDecryptionCount)
{
BOOL rc = FALSE;
DWORD dwLen = dwDataLen;
DWORD Error;
HCRYPTHASH hHash;
BYTE abSignature[A_SHA_DIGEST_LEN];
BYTE rgbSHA[A_SHA_DIGEST_LEN];
DC_BEGIN_FN("TSCAPI_DecryptData");
// data length check
if (dwDataLen <= dwPadLen) {
TRC_ERR((TB, _T("Bad data length, padLen %d is larger than DataLen %d"),
dwPadLen, dwDataLen));
goto done;
}
rc = pCapiData->CapiFunctionTable.pfnCryptDecrypt(pCapiData->hDecKey,
NULL, //Hash
FALSE, //Final
0,
pbData,
&dwLen);
if (!rc) {
TRC_ERR((TB, _T("Error %x during CryptDecrypt!\n"), GetLastError()));
goto done;
}
// Compute signature
if (!HmacHashDataEx(&(pCapiData->CapiFunctionTable), pCapiData->hProv, pbData, dwDataLen - dwPadLen, (BYTE *)&dwDecryptionCount,
sizeof(dwDecryptionCount), pCapiData->hSignKey, &hHash)) {
goto done;
}
if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, abSignature, sizeof(abSignature))) {
goto done;
}
//
// check to see the sigature match.
//
if(!memcmp(
(LPBYTE)abSignature,
pbSignature,
MAX_SIGN_SIZE)) {
rc = TRUE;;
}
done:
DC_END_FN();
return rc;
}