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.
1010 lines
30 KiB
1010 lines
30 KiB
/****************************************************************************/
|
|
/* 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;
|
|
}
|