/****************************************************************************/ /* capienc.cpp */ /* */ /* FIPS encrpt/decrypt */ /* */ /* Copyright (C) 2002-2004 Microsoft Corporation */ /****************************************************************************/ #include extern "C" { #define TRC_GROUP TRC_GROUP_CORE #define TRC_FILE "capienc" #include } #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 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>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> ((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; }