Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1725 lines
42 KiB

/////////////////////////////////////////////////////////////////////////////
// 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;
}