|
|
/////////////////////////////////////////////////////////////////////////////
// FILE : nt_hash.c //
// DESCRIPTION : Crypto CP interfaces: //
// CPBeginHash //
// CPUpdateHash //
// CPDestroyHash //
// AUTHOR : //
// HISTORY : //
// Jan 25 1995 larrys Changed from Nametag //
// Feb 23 1995 larrys Changed NTag_SetLastError to SetLastError //
// May 8 1995 larrys Changes for MAC hashing //
// May 10 1995 larrys added private api calls //
// Jul 13 1995 larrys Changed MAC stuff //
// Aug 07 1995 larrys Added Auto-Inflate to CryptBeginHash //
// Aug 30 1995 larrys Removed RETURNASHVALUE from CryptGetHashValue //
// Sep 19 1995 larrys changed USERDATA to CRYPT_USERDATA //
// Oct 03 1995 larrys check for 0 on Createhash for hKey //
// Oct 05 1995 larrys Changed HashSessionKey to hash key material //
// Oct 13 1995 larrys Removed CPGetHashValue //
// Oct 17 1995 larrys Added MD2 //
// Nov 3 1995 larrys Merge for NT checkin //
// Nov 14 1995 larrys Fixed memory leak //
// Mar 01 1996 rajeshk Added check for Hash Values //
// May 15 1996 larrys Changed NTE_NO_MEMORY to ERROR_NOT_ENOUGHT... //
// Jun 6 1996 a-johnb Added support for SSL 3.0 signatures //
// Apr 25 1997 jeffspel Fix for Bug 76393, GPF on pbData = NULL //
// May 23 1997 jeffspel Added provider type checking //
// //
// Copyright (C) 1993 Microsoft Corporation All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "nt_rsa.h"
#include "tripldes.h"
#include "mac.h"
#include "ssl3.h"
#include "aes.h"
extern BOOL FIsLegalKey( PNTAGUserList pTmpUser, PNTAGKeyList pKey, BOOL fRC2BigKeyOK);
extern DWORD InflateKey( IN PNTAGKeyList pTmpKey);
extern DWORD BlockEncrypt( void EncFun(BYTE *In, BYTE *Out, void *key, int op), PNTAGKeyList pKey, int BlockLen, BOOL Final, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen);
extern DWORD LocalGetHashVal( IN ALG_ID Algid, IN DWORD dwHashFlags, IN OUT BYTE *pbHashData, OUT BYTE *pbHashVal, OUT DWORD *pcbHashVal);
#ifdef CSP_USE_MD5
//
// Function : TestMD5
//
// Description : This function hashes the passed in message with the MD5 hash
// algorithm and returns the resulting hash value.
//
BOOL TestMD5( BYTE *pbMsg, DWORD cbMsg, BYTE *pbHash) { MD5_CTX MD5; BOOL fRet = FALSE;
// Check length for input data
if (0 == cbMsg) goto ErrorExit;
// Initialize MD5
MD5Init(&MD5);
// Compute MD5
MD5Update(&MD5, pbMsg, cbMsg);
MD5Final(&MD5); memcpy(pbHash, MD5.digest, MD5DIGESTLEN);
fRet = TRUE;
ErrorExit: return fRet; } #endif // CSP_USE_MD5
#ifdef CSP_USE_SHA1
//
// Function : TestSHA1
//
// Description : This function hashes the passed in message with the SHA1 hash
// algorithm and returns the resulting hash value.
//
BOOL TestSHA1( BYTE *pbMsg, DWORD cbMsg, BYTE *pbHash) { A_SHA_CTX HashContext; BOOL fRet = FALSE;
// Check length for input data
if (0 == cbMsg) goto ErrorExit;
// Initialize SHA
A_SHAInit(&HashContext);
// Compute SHA
A_SHAUpdate(&HashContext, pbMsg, cbMsg);
A_SHAFinal(&HashContext, pbHash);
fRet = TRUE;
ErrorExit: return fRet; } #endif // CSP_USE_SHA1
BOOL ValidHashAlgid( PNTAGUserList pTmpUser, ALG_ID Algid) { if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && ((CALG_MD2 == Algid) || (CALG_MD4 == Algid))) return FALSE; else return TRUE; }
// local function for creating hashes
DWORD LocalCreateHash( IN ALG_ID Algid, OUT BYTE **ppbHashData, OUT DWORD *pcbHashData) { DWORD dwReturn = ERROR_INTERNAL_ERROR;
switch (Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: { MD2_object *pMD2Hash;
pMD2Hash = (MD2_object *)_nt_malloc(sizeof(MD2_object)); if (NULL == pMD2Hash) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
// Set up the Initial MD2 Hash State
memset ((BYTE *)pMD2Hash, 0, sizeof(MD2_object)); pMD2Hash->FinishFlag = FALSE;
*pcbHashData = sizeof(MD2_object); *ppbHashData = (LPBYTE)pMD2Hash; break; } #endif
#ifdef CSP_USE_MD4
case CALG_MD4: { MD4_object *pMD4Hash;
pMD4Hash = (MD4_object *)_nt_malloc(sizeof(MD4_object)); if (NULL == pMD4Hash) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
// Set up the Initial MD4 Hash State
memset ((BYTE *)pMD4Hash, 0, sizeof(MD4_object)); pMD4Hash->FinishFlag = FALSE; MDbegin(&pMD4Hash->MD);
*pcbHashData = sizeof(MD4_object); *ppbHashData = (BYTE*)pMD4Hash; break; } #endif
#ifdef CSP_USE_MD5
case CALG_MD5: { MD5_object *pMD5Hash;
pMD5Hash = (MD5_object *)_nt_malloc(sizeof(MD5_object)); if (NULL == pMD5Hash) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
// Set up the our state
pMD5Hash->FinishFlag = FALSE; MD5Init(pMD5Hash);
*ppbHashData = (BYTE*)pMD5Hash; *pcbHashData = sizeof(MD5_object); break; } #endif
#ifdef CSP_USE_SHA
case CALG_SHA: { A_SHA_CTX *pSHAHash;
pSHAHash = (A_SHA_CTX *)_nt_malloc(sizeof(A_SHA_CTX)); if (NULL == pSHAHash) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
// Set up our state
A_SHAInit(pSHAHash); pSHAHash->FinishFlag = FALSE;
*ppbHashData = (BYTE*)pSHAHash; *pcbHashData = sizeof(A_SHA_CTX); break; } #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
/*
- CPBeginHash - * Purpose: * initate the hashing of a stream of data * * * Parameters: * IN hUID - Handle to the user identifcation * IN Algid - Algorithm identifier of the hash algorithm * to be used * IN hKey - Optional key for MAC algorithms * IN dwFlags - Flags values * OUT pHash - Handle to hash object * * Returns: */
BOOL WINAPI CPCreateHash( IN HCRYPTPROV hUID, IN ALG_ID Algid, IN HCRYPTKEY hKey, IN DWORD dwFlags, OUT HCRYPTHASH *phHash) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; PNTAGHashList pCurrentHash = NULL; PNTAGKeyList pTmpKey; #ifdef CSP_USE_SSL3
PSCH_HASH pSChHash; #endif // CSP_USE_SSL3
BOOL fRet; DWORD dwSts;
EntryPoint if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check if the user handle is valid
pTmpUser = NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if (!ValidHashAlgid(pTmpUser, Algid)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
// Prepare the structure to be used as the hash handle
pCurrentHash = (PNTAGHashList)_nt_malloc(sizeof(NTAGHashList)); if (NULL == pCurrentHash) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memset(pCurrentHash, 0, sizeof(NTAGHashList)); pCurrentHash->Algid = Algid; pCurrentHash->hUID = hUID;
// determine which hash algorithm is to be used
switch (Algid) { #ifdef CSP_USE_MAC
case CALG_MAC: { MACstate *pMACVal;
if (hKey == 0) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
dwSts = NTLValidate(hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if (pTmpKey->Mode != CRYPT_MODE_CBC) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// Check if we should do an auto-inflate
if (pTmpKey->pData == NULL) { dwSts = InflateKey(pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
pMACVal = (MACstate *)_nt_malloc(sizeof(MACstate)); if (NULL == pMACVal) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pCurrentHash->pHashData = pMACVal; pCurrentHash->dwDataLen = sizeof(MACstate); pCurrentHash->hKey = hKey; pMACVal->dwBufLen = 0; pMACVal->FinishFlag = FALSE; break; } #endif
case CALG_HMAC: { if (hKey == 0) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
dwSts = NTLValidate(hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
pCurrentHash->hKey = hKey; break; }
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5: { pCurrentHash->pHashData = _nt_malloc(SSL3_SHAMD5_LEN); if (NULL == pCurrentHash->pHashData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pCurrentHash->dwDataLen = SSL3_SHAMD5_LEN; break; } #endif
#ifdef CSP_USE_SSL3
case CALG_SCHANNEL_MASTER_HASH: { if (0 == hKey) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
dwSts = NTLValidate(hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if ((CALG_SSL3_MASTER != pTmpKey->Algid) && (CALG_PCT1_MASTER != pTmpKey->Algid) && (pTmpKey->cbKeyLen > MAX_PREMASTER_LEN)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
pCurrentHash->dwDataLen = sizeof(SCH_HASH); pCurrentHash->pHashData = (BYTE *)_nt_malloc(pCurrentHash->dwDataLen); if (NULL == pCurrentHash->pHashData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } memset(pCurrentHash->pHashData, 0, pCurrentHash->dwDataLen); pSChHash = (PSCH_HASH)pCurrentHash->pHashData; pSChHash->ProtocolAlgid = pTmpKey->Algid;
dwSts = SChGenMasterKey(pTmpKey, pSChHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; }
case CALG_TLS1PRF: { PRF_HASH *pPRFHash; PSCH_KEY pSChKey;
if (0 == hKey) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
dwSts = NTLValidate(hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if (CALG_TLS1_MASTER != pTmpKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// check if the master key is finished
pSChKey = (PSCH_KEY)pTmpKey->pData; if ((!pSChKey->fFinished) || (TLS_MASTER_LEN != pTmpKey->cbKeyLen)) { dwReturn = (DWORD)NTE_BAD_KEY_STATE; goto ErrorExit; }
pCurrentHash->dwDataLen = sizeof(PRF_HASH); pCurrentHash->pHashData = (BYTE *)_nt_malloc(pCurrentHash->dwDataLen); if (NULL == pCurrentHash->pHashData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } memset(pCurrentHash->pHashData, 0, pCurrentHash->dwDataLen); pPRFHash = (PRF_HASH*)pCurrentHash->pHashData; memcpy(pPRFHash->rgbMasterKey, pTmpKey->pKeyValue, TLS_MASTER_LEN); break; } #endif // CSP_USE_SSL3
default: if (hKey != 0) { dwReturn = NTE_BAD_KEY; goto ErrorExit; }
dwSts = LocalCreateHash(Algid, (BYTE**)&pCurrentHash->pHashData, &pCurrentHash->dwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
dwSts = NTLMakeItem(phHash, HASH_HANDLE, pCurrentHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) { if (NULL != pCurrentHash) { if (pCurrentHash->pHashData) _nt_free(pCurrentHash->pHashData, pCurrentHash->dwDataLen); _nt_free(pCurrentHash, sizeof(NTAGHashList)); } SetLastError(dwReturn); } return fRet; }
DWORD LocalHashData( IN ALG_ID Algid, IN OUT BYTE *pbHashData, IN BYTE *pbData, IN DWORD cbData) { DWORD dwReturn = ERROR_INTERNAL_ERROR; BYTE *ptmp; DWORD BytePos;
switch (Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: { MD2_object *pMD2Hash;
// make sure the hash is updatable
pMD2Hash = (MD2_object *)pbHashData; if (pMD2Hash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
if (0 != MD2Update(&pMD2Hash->MD, pbData, cbData)) { // This is a reasonable return code, since currently
// the only value MD2Update returns is zero.
dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; }
break; } #endif
#ifdef CSP_USE_MD4
case CALG_MD4: { MD4_object *pMD4Hash; int nSts;
pMD4Hash = (MD4_object *)pbHashData;
// make sure the hash is updatable
if (pMD4Hash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
// MD4 hashes when the size == MD4BLOCKSIZE and finishes the
// hash when the given size is < MD4BLOCKSIZE.
// So, ensure that the user always gives a full block here --
// when NTagFinishHash is called, we'll send the last bit and
// that'll finish off the hash.
ptmp = (BYTE *)pbData; for (;;) { // check if there's plenty of room in the buffer
if (cbData < (MD4BLOCKSIZE - pMD4Hash->BufLen)) { // just append to whatever's already
memcpy(pMD4Hash->Buf + pMD4Hash->BufLen, ptmp, cbData);
// set of the trailing buffer length field
pMD4Hash->BufLen += (BYTE)cbData; break; }
// determine what we need to fill the buffer, then do it.
BytePos = MD4BLOCKSIZE - pMD4Hash->BufLen; ASSERT(BytePos <= dwTmpLen); memcpy(pMD4Hash->Buf + pMD4Hash->BufLen, ptmp, BytePos);
// The buffer is now full, process it.
nSts = MDupdate(&pMD4Hash->MD, pMD4Hash->Buf, MD4BYTESTOBITS(MD4BLOCKSIZE)); if (MD4_SUCCESS != nSts) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; }
// now it's empty.
pMD4Hash->BufLen = 0;
// we processed some bytes, so reflect that and try again
cbData -= BytePos; ptmp += BytePos;
if (cbData == 0) break; } break; } #endif
#ifdef CSP_USE_MD5
case CALG_MD5: { MD5_object *pMD5Hash;
// make sure the hash is updatable
pMD5Hash = (MD5_object *)pbHashData; if (pMD5Hash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
MD5Update(pMD5Hash, pbData, cbData); break; } #endif
#ifdef CSP_USE_SHA
case CALG_SHA: { A_SHA_CTX *pSHAHash;
// make sure the hash is updatable
pSHAHash = (A_SHA_CTX *)pbHashData; if (pSHAHash->FinishFlag) { dwReturn = (DWORD) NTE_BAD_HASH_STATE; goto ErrorExit; }
A_SHAUpdate(pSHAHash, pbData, cbData); break; } #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
/*static*/ DWORD LocalMACData( IN HCRYPTPROV hUID, IN PNTAGHashList pTmpHash, IN CONST BYTE *pbData, IN DWORD cbData) { DWORD dwReturn = ERROR_INTERNAL_ERROR; MACstate *pMAC; PNTAGKeyList pTmpKey; BYTE *pbTmp; DWORD dwTmpLen; BYTE *pb = NULL; DWORD cb; DWORD i; BYTE *pbJunk = NULL; DWORD dwBufSlop; DWORD dwEncLen; DWORD dwSts; PBYTE pbKeyHash = NULL; DWORD cbKeyHash = 0; dwTmpLen = cbData; pbTmp = (BYTE *) pbData;
switch (pTmpHash->Algid) { #ifdef CSP_USE_MAC
case CALG_MAC: { pMAC = (MACstate *)pTmpHash->pHashData;
// make sure the hash is updatable
if (pMAC->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
dwSts = NTLValidate(pTmpHash->hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if (pMAC->dwBufLen + dwTmpLen <= pTmpKey->dwBlockLen) { memcpy(pMAC->Buffer + pMAC->dwBufLen, pbTmp, dwTmpLen); pMAC->dwBufLen += dwTmpLen; dwReturn = ERROR_SUCCESS; goto ErrorExit; }
memcpy(pMAC->Buffer+pMAC->dwBufLen, pbTmp, (pTmpKey->dwBlockLen - pMAC->dwBufLen));
dwTmpLen -= (pTmpKey->dwBlockLen - pMAC->dwBufLen); pbTmp += (pTmpKey->dwBlockLen - pMAC->dwBufLen);
pMAC->dwBufLen = pTmpKey->dwBlockLen;
switch (pTmpKey->Algid) { case CALG_RC2: dwSts = BlockEncrypt(RC2, pTmpKey, RC2_BLOCKLEN, FALSE, pMAC->Buffer, &pMAC->dwBufLen, MAX_BLOCKLEN); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case CALG_DES: dwSts = BlockEncrypt(des, pTmpKey, DES_BLOCKLEN, FALSE, pMAC->Buffer, &pMAC->dwBufLen, MAX_BLOCKLEN); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
#ifdef CSP_USE_3DES
case CALG_3DES_112: case CALG_3DES: dwSts = BlockEncrypt(tripledes, pTmpKey, DES_BLOCKLEN, FALSE, pMAC->Buffer, &pMAC->dwBufLen, MAX_BLOCKLEN); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif
#ifdef CSP_USE_AES
case CALG_AES_128: case CALG_AES_192: case CALG_AES_256: dwSts = BlockEncrypt(aes, pTmpKey, pTmpKey->dwBlockLen, FALSE, pMAC->Buffer, &pMAC->dwBufLen, MAX_BLOCKLEN); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif
}
pMAC->dwBufLen = 0;
dwBufSlop = dwTmpLen % pTmpKey->dwBlockLen; if (dwBufSlop == 0) { dwBufSlop = pTmpKey->dwBlockLen; }
pbJunk = _nt_malloc(dwTmpLen); if (NULL == pbJunk) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pbJunk, pbTmp, dwTmpLen - dwBufSlop); dwEncLen = dwTmpLen - dwBufSlop;
switch (pTmpKey->Algid) { case CALG_RC2: dwSts = BlockEncrypt(RC2, pTmpKey, RC2_BLOCKLEN, FALSE, pbJunk, &dwEncLen, dwTmpLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case CALG_DES: dwSts = BlockEncrypt(des, pTmpKey, DES_BLOCKLEN, FALSE, pbJunk, &dwEncLen, dwTmpLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
#ifdef CSP_USE_3DES
case CALG_3DES_112: case CALG_3DES: dwSts = BlockEncrypt(tripledes, pTmpKey, DES_BLOCKLEN, FALSE, pbJunk, &dwEncLen, dwTmpLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif
#ifdef CSP_USE_AES
case CALG_AES_128: case CALG_AES_192: case CALG_AES_256: dwSts = BlockEncrypt(aes, pTmpKey, pTmpKey->dwBlockLen, FALSE, pbJunk, &dwEncLen, dwTmpLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif
}
memcpy(pMAC->Buffer, pbTmp + dwEncLen, dwBufSlop); pMAC->dwBufLen = dwBufSlop; break; } #endif
case CALG_HMAC: { if (!(pTmpHash->HMACState & HMAC_STARTED)) { dwSts = NTLValidate(pTmpHash->hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
// If key is longer than block length, hash the key
// data first
if (pTmpKey->cbKeyLen > HMAC_DEFAULT_STRING_LEN) { dwSts = LocalCreateHash(pTmpHash->HMACAlgid, &pbKeyHash, &cbKeyHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwSts = LocalHashData(pTmpHash->HMACAlgid, pbKeyHash, pTmpKey->pKeyValue, pTmpKey->cbKeyLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } pb = (BYTE *)_nt_malloc(HMAC_DEFAULT_STRING_LEN); if (NULL == pb) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
cb = HMAC_DEFAULT_STRING_LEN; dwSts = LocalGetHashVal(pTmpHash->HMACAlgid, 0, pbKeyHash, pb, &cb); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
for (i = 0; i < HMAC_DEFAULT_STRING_LEN; i++) pb[i] ^= (pTmpHash->pbHMACInner)[i];
cb = HMAC_DEFAULT_STRING_LEN; } else { if (pTmpKey->cbKeyLen < pTmpHash->cbHMACInner) cb = pTmpHash->cbHMACInner; else cb = pTmpKey->cbKeyLen; pb = (BYTE *)_nt_malloc(cb); if (NULL == pb) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } memcpy(pb, pTmpHash->pbHMACInner, pTmpHash->cbHMACInner); // currently no support for byte reversed keys with HMAC
for (i=0;i<pTmpKey->cbKeyLen;i++) pb[i] ^= (pTmpKey->pKeyValue)[i]; }
dwSts = LocalHashData(pTmpHash->HMACAlgid, pTmpHash->pHashData, pb, cb); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
pTmpHash->HMACState |= HMAC_STARTED; memnuke(pb, cb); memnuke(pbKeyHash, cbKeyHash); }
dwSts = LocalHashData(pTmpHash->HMACAlgid, pTmpHash->pHashData, (BYTE*)pbData, cbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
break; }
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: if (pbJunk) _nt_free(pbJunk, dwTmpLen); if (pb) _nt_free(pb, cb); if (pbKeyHash) _nt_free(pbKeyHash, cbKeyHash); return dwReturn; }
/*
- CPHashData - * Purpose: * Compute the cryptograghic hash on a stream of data * * * Parameters: * IN hUID - Handle to the user identifcation * IN hHash - Handle to hash object * IN pbData - Pointer to data to be hashed * IN dwDataLen - Length of the data to be hashed * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPHashData( IN HCRYPTPROV hUID, IN HCRYPTHASH hHash, IN CONST BYTE *pbData, IN DWORD dwDataLen, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pTmpHash; PNTAGUserList pUser; BOOL fRet; DWORD dwSts;
EntryPoint if (0 != (dwFlags & ~(CRYPT_USERDATA))) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
pUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if (0 == dwDataLen) { dwReturn = ERROR_SUCCESS; goto ErrorExit; }
if (NULL == pbData) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { // NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; }
if (pTmpHash->HashFlags & HF_VALUE_SET) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
switch (pTmpHash->Algid) { #ifdef CSP_USE_MAC
case CALG_MAC: #endif // CSP_USE_MAC
case CALG_HMAC: dwSts = LocalMACData(hUID, pTmpHash, pbData, dwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
default: dwSts = LocalHashData(pTmpHash->Algid, pTmpHash->pHashData, (BYTE*)pbData, dwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
pTmpHash->dwHashState |= DATA_IN_HASH;
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ DWORD SetupKeyToBeHashed( PNTAGKeyList pKey, BYTE **ppbData, DWORD *pcbData, DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD cb; DWORD i;
*ppbData = NULL; cb = pKey->cbKeyLen;
*ppbData = (BYTE *)_nt_malloc(cb); if (NULL == *ppbData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
if (CRYPT_LITTLE_ENDIAN & dwFlags) { memcpy(*ppbData, pKey->pKeyValue, cb); } else { // Reverse the session key bytes
for (i = 0; i < cb; i++) (*ppbData)[i] = (pKey->pKeyValue)[cb - i - 1]; }
*pcbData = cb; dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
/*
- CPHashSessionKey - * Purpose: * Compute the cryptograghic hash on a key object. * * * Parameters: * IN hUID - Handle to the user identifcation * IN hHash - Handle to hash object * IN hKey - Handle to a key object * IN dwFlags - Flags values * * Returns: * CRYPT_FAILED * CRYPT_SUCCEED */
BOOL WINAPI CPHashSessionKey( IN HCRYPTPROV hUID, IN HCRYPTHASH hHash, IN HCRYPTKEY hKey, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pTmpHash; PNTAGKeyList pTmpKey; PNTAGUserList pTmpUser; DWORD dwDataLen; BYTE *pbData = NULL; DWORD BytePos; #ifdef CSP_USE_SSL3
PSCH_KEY pSChKey; #endif // CSP_USE_SSL3
BOOL fRet; DWORD dwSts;
EntryPoint if (dwFlags & ~(CRYPT_LITTLE_ENDIAN)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check the user identification
pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; }
if (pTmpHash->HashFlags & HF_VALUE_SET) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
dwSts = NTLValidate((HNTAG)hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if (!FIsLegalKey(pTmpUser, pTmpKey, FALSE)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
#ifdef CSP_USE_SSL3
if ((CALG_SSL3_MASTER == pTmpKey->Algid) || (CALG_TLS1_MASTER == pTmpKey->Algid) || (CALG_PCT1_MASTER == pTmpKey->Algid)) { if (NULL == pTmpKey->pData) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } pSChKey = (PSCH_KEY)pTmpKey->pData; if (!pSChKey->fFinished) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } } #endif // CSP_USE_SSL3
#if 0
// Check if we should do an auto-inflate
if (pTmpKey->pData == NULL) { if (NTAG_FAILED(CPInflateKey(pTmpKey))) { dwReturn = GetLastError(); goto ErrorExit; } } #endif
if ((CALG_DES == pTmpKey->Algid) || (CALG_3DES == pTmpKey->Algid) || (CALG_3DES_112 == pTmpKey->Algid)) { if (PROV_RSA_SCHANNEL != pTmpUser->dwProvType) { if ((POLICY_MS_STRONG == pTmpUser->dwCspTypeId) || (!(pTmpUser->Rights & CRYPT_DES_HASHKEY_BACKWARDS))) { desparityonkey(pTmpKey->pKeyValue, pTmpKey->cbKeyLen); } } }
dwSts = SetupKeyToBeHashed(pTmpKey, &pbData, &dwDataLen, dwFlags); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
switch (pTmpHash->Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: { MD2_object *pMD2Hash;
pMD2Hash = (MD2_object *)pTmpHash->pHashData;
// make sure the hash is updatable
if (pMD2Hash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
if (0 != MD2Update(&pMD2Hash->MD, pbData, dwDataLen)) { // This is reasonable, since MD2Update only returns zero.
dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; } break; } #endif
#ifdef CSP_USE_MD4
case CALG_MD4: { MD4_object *pMD4Hash; int nSts;
pMD4Hash = (MD4_object *)pTmpHash->pHashData;
// make sure the hash is updatable
if (pMD4Hash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
for (;;) { // check if there's plenty of room in the buffer
if ((pMD4Hash->BufLen + dwDataLen) < MD4BLOCKSIZE) { // just append to whatever's already
memcpy(pMD4Hash->Buf + pMD4Hash->BufLen, pbData, dwDataLen);
// set of the trailing buffer length field
pMD4Hash->BufLen += (BYTE)dwDataLen; break; }
// determine what we need to fill the buffer, then do it.
BytePos = MD4BLOCKSIZE - pMD4Hash->BufLen; memcpy(pMD4Hash->Buf + pMD4Hash->BufLen, pbData, BytePos);
// The buffer is now full, process it.
nSts = MDupdate(&pMD4Hash->MD, pMD4Hash->Buf, MD4BYTESTOBITS(MD4BLOCKSIZE)); if (MD4_SUCCESS != nSts) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; }
// now it's empty.
pMD4Hash->BufLen = 0;
// we processed some bytes, so reflect that and try again
dwDataLen -= BytePos; if (dwDataLen == 0) break; } break; } #endif
#ifdef CSP_USE_MD5
case CALG_MD5: { MD5_object *pMD5Hash;
pMD5Hash = (MD5_object *)pTmpHash->pHashData;
// make sure the hash is updatable
if (pMD5Hash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
MD5Update(pMD5Hash, pbData, dwDataLen); break; } #endif
#ifdef CSP_USE_SHA
case CALG_SHA: { A_SHA_CTX *pSHAHash;
pSHAHash = (A_SHA_CTX *)pTmpHash->pHashData;
// make sure the hash is updatable
if (pSHAHash->FinishFlag) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
A_SHAUpdate(pSHAHash, (BYTE *)pbData, dwDataLen); break; } #endif
#ifdef CSP_USE_MAC
case CALG_MAC: #endif // CSP_USE_MAC
case CALG_HMAC: dwSts = LocalMACData(hUID, pTmpHash, pbData, dwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
pTmpHash->dwHashState |= DATA_IN_HASH;
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (pbData) _nt_free(pbData, dwDataLen); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ void FreeHash( IN PNTAGHashList pHash) { if (pHash) { if (pHash->pHashData) _nt_free(pHash->pHashData, pHash->dwDataLen); if (pHash->pbHMACInner) _nt_free(pHash->pbHMACInner, pHash->cbHMACInner); if (pHash->pbHMACOuter) _nt_free(pHash->pbHMACOuter, pHash->cbHMACOuter); if (pHash->fTempKey) CPDestroyKey(pHash->hUID, pHash->hKey); _nt_free(pHash, sizeof(NTAGHashList)); } }
/*
- CPDestroyHash - * Purpose: * Destory the hash object * * * Parameters: * IN hUID - Handle to the user identifcation * IN hHash - Handle to hash object * * Returns: */
BOOL WINAPI CPDestroyHash( IN HCRYPTPROV hUID, IN HCRYPTHASH hHash) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pTmpHash; BOOL fRet; DWORD dwSts;
EntryPoint // check the user identification
if (NULL == NTLCheckList(hUID, USER_HANDLE)) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { // NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; }
switch (pTmpHash->Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: #endif
#ifdef CSP_USE_MD4
case CALG_MD4: #endif
#ifdef CSP_USE_MD5
case CALG_MD5: #endif
#ifdef CSP_USE_SHA
case CALG_SHA: #endif
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5: #endif
#ifdef CSP_USE_MAC
case CALG_MAC: case CALG_HMAC: #endif
#ifdef CSP_USE_SSL3
case CALG_SCHANNEL_MASTER_HASH: case CALG_TLS1PRF: #endif
if (CALG_SCHANNEL_MASTER_HASH == pTmpHash->Algid) { FreeSChHash((PSCH_HASH)pTmpHash->pHashData); } memnuke(pTmpHash->pHashData, pTmpHash->dwDataLen); break;
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
// Remove from internal list first so others can't get to it, then free.
NTLDelete(hHash); FreeHash(pTmpHash);
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ DWORD CopyHash( IN PNTAGHashList pOldHash, OUT PNTAGHashList *ppNewHash) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pNewHash; BOOL fSts;
pNewHash = (PNTAGHashList)_nt_malloc(sizeof(NTAGHashList)); if (NULL == pNewHash) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pNewHash, pOldHash, sizeof(NTAGHashList)); pNewHash->fTempKey = FALSE; pNewHash->hKey = 0; pNewHash->dwDataLen = 0; pNewHash->pHashData = NULL; pNewHash->cbHMACInner = 0; pNewHash->pbHMACInner = NULL; pNewHash->cbHMACOuter = 0; pNewHash->pbHMACOuter = NULL;
//
// Duplicate the associated key.
//
if (0 != pOldHash->hKey) { fSts = CPDuplicateKey(pNewHash->hUID, pOldHash->hKey, NULL, 0, &pNewHash->hKey); if (!fSts) { dwReturn = GetLastError(); goto ErrorExit; }
pNewHash->fTempKey = TRUE; }
//
// Duplicate the hash data.
//
if (0 < pOldHash->dwDataLen) { pNewHash->pHashData = (BYTE*)_nt_malloc(pOldHash->dwDataLen); if (NULL == pNewHash->pHashData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pNewHash->dwDataLen = pOldHash->dwDataLen; memcpy(pNewHash->pHashData, pOldHash->pHashData, pOldHash->dwDataLen); }
//
// Duplicate HMAC Inner.
//
if (0 < pOldHash->cbHMACInner) { pNewHash->pbHMACInner = (LPBYTE)_nt_malloc(pOldHash->cbHMACInner); if (NULL == pNewHash->pbHMACInner) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pNewHash->cbHMACInner = pOldHash->cbHMACInner; memcpy(pNewHash->pbHMACInner, pOldHash->pbHMACInner, pOldHash->cbHMACInner); }
//
// Duplicate HMAC Outer.
//
if (0 < pOldHash->cbHMACOuter) { pNewHash->pbHMACOuter = (LPBYTE)_nt_malloc(pOldHash->cbHMACOuter); if (NULL == pNewHash->pbHMACOuter) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pNewHash->cbHMACOuter = pOldHash->cbHMACOuter; memcpy(pNewHash->pbHMACOuter, pOldHash->pbHMACOuter, pOldHash->cbHMACOuter); }
//
// Return to the caller.
//
*ppNewHash = pNewHash; return ERROR_SUCCESS;
ErrorExit: FreeHash(pNewHash); return dwReturn; }
/*
- CPDuplicateHash - * Purpose: * Duplicates the state of a hash and returns a handle to it * * Parameters: * IN hUID - Handle to a CSP * IN hHash - Handle to a hash * IN pdwReserved - Reserved * IN dwFlags - Flags * IN phHash - Handle to the new hash * * Returns: */
BOOL WINAPI CPDuplicateHash( IN HCRYPTPROV hUID, IN HCRYPTHASH hHash, IN DWORD *pdwReserved, IN DWORD dwFlags, IN HCRYPTHASH *phHash) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pTmpHash; PNTAGHashList pNewHash = NULL; BOOL fRet; DWORD dwSts;
EntryPoint if (NULL != pdwReserved) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
if (0 != dwFlags) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = NTLValidate((HNTAG)hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; }
dwSts = CopyHash(pTmpHash, &pNewHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwSts = NTLMakeItem(phHash, HASH_HANDLE, (void *)pNewHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) { FreeHash(pNewHash); SetLastError(dwReturn); } return fRet; }
|