mirror of https://github.com/lianthony/NT4.0
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.
1004 lines
26 KiB
1004 lines
26 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 //
|
|
// //
|
|
// Copyright (C) 1993 Microsoft Corporation All Rights Reserved //
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "precomp.h"
|
|
#include "nt_rsa.h"
|
|
#include "mac.h"
|
|
|
|
BOOL BlockEncrypt(void EncFun(BYTE *In, BYTE *Out, void *key, int op),
|
|
PNTAGKeyList pKey,
|
|
int BlockLen,
|
|
BOOL Final,
|
|
BYTE *pbData,
|
|
DWORD *pdwDataLen,
|
|
DWORD dwBufLen);
|
|
|
|
/*
|
|
- 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 CPCreateHash(IN HCRYPTPROV hUID,
|
|
IN ALG_ID Algid,
|
|
IN HCRYPTKEY hKey,
|
|
IN DWORD dwFlags,
|
|
OUT HCRYPTHASH *phHash)
|
|
{
|
|
PNTAGHashList pCurrentHash;
|
|
PNTAGKeyList pTmpKey;
|
|
WORD count = 0;
|
|
|
|
if (dwFlags != 0)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_FLAGS);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// check if the user handle is valid
|
|
if (NTLCheckList (hUID, USER_HANDLE) == NULL)
|
|
{
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// Prepare the structure to be used as the hash handle
|
|
if ((pCurrentHash =
|
|
(PNTAGHashList) _nt_malloc(sizeof(NTAGHashList))) == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
pCurrentHash->Algid = Algid;
|
|
pCurrentHash->hUID = hUID;
|
|
pCurrentHash->HashFlags = 0;
|
|
|
|
// determine which hash algorithm is to be used
|
|
switch (Algid)
|
|
{
|
|
|
|
#ifdef CSP_USE_MAC
|
|
|
|
case CALG_MAC:
|
|
{
|
|
MACstate *pMACVal;
|
|
|
|
if (hKey == 0)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError((DWORD) NTE_BAD_KEY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pTmpKey = (PNTAGKeyList) NTLValidate(hKey, hUID,
|
|
KEY_HANDLE)) == NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
if (GetLastError() == NTE_FAIL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_KEY);
|
|
}
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if (pTmpKey->Mode != CRYPT_MODE_CBC)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError((DWORD) NTE_BAD_KEY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// Check if we should do an auto-inflate
|
|
if (pTmpKey->pData == NULL)
|
|
{
|
|
if (NTAG_FAILED(CPInflateKey(hUID, hKey, 0)))
|
|
{
|
|
return NTF_FAILED;
|
|
}
|
|
}
|
|
|
|
if ((pMACVal = (MACstate *)_nt_malloc(sizeof(MACstate)))==NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
pCurrentHash->pHashData = pMACVal;
|
|
pCurrentHash->dwDataLen = sizeof(MACstate);
|
|
pMACVal->dwBufLen = 0;
|
|
pMACVal->hKey = hKey;
|
|
pMACVal->FinishFlag = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CSP_USE_MD2
|
|
|
|
case CALG_MD2:
|
|
{
|
|
MD2_object *pMD2Hash;
|
|
|
|
if (hKey != 0)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pMD2Hash = (MD2_object *)_nt_malloc(sizeof(MD2_object))) == NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
memset ((BYTE *)pMD2Hash, 0, sizeof(MD2_object));
|
|
|
|
pCurrentHash->pHashData = pMD2Hash;
|
|
pCurrentHash->dwDataLen = sizeof(MD2_object);
|
|
|
|
// Set up the Initial MD2 Hash State
|
|
pMD2Hash->FinishFlag = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CSP_USE_MD4
|
|
|
|
case CALG_MD4:
|
|
{
|
|
MD4_object *pMD4Hash;
|
|
|
|
if (hKey != 0)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pMD4Hash = (MD4_object *)_nt_malloc(sizeof(MD4_object))) == NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
memset ((BYTE *)pMD4Hash, 0, sizeof(MD4_object));
|
|
|
|
// Set up our State
|
|
pCurrentHash->pHashData = pMD4Hash;
|
|
pCurrentHash->dwDataLen = sizeof(MD4_object);
|
|
|
|
// Set up the Initial MD4 Hash State
|
|
pMD4Hash->FinishFlag = FALSE;
|
|
MDbegin(&pMD4Hash->MD);
|
|
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CSP_USE_MD5
|
|
|
|
case CALG_MD5:
|
|
{
|
|
MD5_object *pMD5Hash;
|
|
|
|
if (hKey != 0)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pMD5Hash = (MD5_object *) _nt_malloc(sizeof(MD5_object))) == NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// Set up the our state
|
|
pCurrentHash->pHashData = pMD5Hash;
|
|
pCurrentHash->dwDataLen = sizeof(MD5_object);
|
|
|
|
pMD5Hash->FinishFlag = FALSE;
|
|
|
|
// call the code to actually begin an MD5 hash
|
|
MD5Init(pMD5Hash);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CSP_USE_SHA
|
|
|
|
case CALG_SHA:
|
|
{
|
|
A_SHA_CTX *pSHAHash;
|
|
|
|
if ((pSHAHash = (A_SHA_CTX *)_nt_malloc(sizeof(A_SHA_CTX))) == NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// Set up our state
|
|
pCurrentHash->pHashData = pSHAHash;
|
|
pCurrentHash->dwDataLen = sizeof(A_SHA_CTX);
|
|
|
|
A_SHAInit(pSHAHash);
|
|
pSHAHash->FinishFlag = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CSP_USE_SSL3SHAMD5
|
|
case CALG_SSL3_SHAMD5:
|
|
|
|
if ((pCurrentHash->pHashData = _nt_malloc(SSL3_SHAMD5_LEN)) == NULL)
|
|
{
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
pCurrentHash->dwDataLen = SSL3_SHAMD5_LEN;
|
|
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
SetLastError((DWORD) NTE_BAD_ALGID);
|
|
return NTF_FAILED;
|
|
break;
|
|
}
|
|
|
|
#ifdef STT
|
|
ASSERT(pCurrentHash);
|
|
ASSERT(pCurrentHash->pHashData);
|
|
ASSERT(pCurrentHash->dwDataLen);
|
|
#endif
|
|
|
|
if (NTLMakeItem(phHash, HASH_HANDLE, pCurrentHash) == NTF_FAILED)
|
|
{
|
|
_nt_free(pCurrentHash->pHashData, pCurrentHash->dwDataLen);
|
|
_nt_free(pCurrentHash, sizeof(NTAGHashList));
|
|
return NTF_FAILED; // error already set
|
|
}
|
|
|
|
return NTF_SUCCEED;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
- 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 CPHashData(IN HCRYPTPROV hUID,
|
|
IN HCRYPTHASH hHash,
|
|
IN CONST BYTE *pbData,
|
|
IN DWORD dwDataLen,
|
|
IN DWORD dwFlags)
|
|
{
|
|
DWORD BytePos;
|
|
PNTAGHashList pTmpHash;
|
|
BOOL f;
|
|
BYTE *pbTmp;
|
|
DWORD dwTmpLen;
|
|
PNTAGUserList pUser;
|
|
|
|
if ((dwFlags & ~(CRYPT_USERDATA)) != 0)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_FLAGS);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pUser = (PNTAGUserList) NTLCheckList(hUID, USER_HANDLE)) == NULL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_UID);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if (dwFlags & CRYPT_USERDATA)
|
|
{
|
|
if (dwDataLen != 0)
|
|
{
|
|
return NTE_BAD_LEN;
|
|
}
|
|
|
|
if (CryptGetUserData(pUser->hPrivuid, &pbTmp,
|
|
&dwTmpLen) == CPPAPI_FAILED)
|
|
{
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (dwDataLen == 0)
|
|
{
|
|
return NTF_SUCCEED;
|
|
}
|
|
|
|
dwTmpLen = dwDataLen;
|
|
pbTmp = (BYTE *) pbData;
|
|
}
|
|
|
|
if ((pTmpHash = (PNTAGHashList) NTLValidate(hHash, hUID,
|
|
HASH_HANDLE)) == NULL)
|
|
{
|
|
// NTLValidate doesn't know what error to set
|
|
// so it set NTE_FAIL -- fix it up.
|
|
if (GetLastError() == NTE_FAIL)
|
|
SetLastError((DWORD) NTE_BAD_HASH);
|
|
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if (pTmpHash->HashFlags & HF_VALUE_SET)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
switch (pTmpHash->Algid)
|
|
{
|
|
|
|
#ifdef CSP_USE_MAC
|
|
|
|
case CALG_MAC:
|
|
{
|
|
MACstate *pMAC;
|
|
BYTE *pbJunk;
|
|
PNTAGKeyList pTmpKey;
|
|
DWORD dwBufSlop, dwEncLen;
|
|
|
|
pMAC = (MACstate *)pTmpHash->pHashData;
|
|
|
|
// make sure the hash is updatable
|
|
if (pMAC->FinishFlag == TRUE)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pTmpKey = (PNTAGKeyList) NTLValidate(pMAC->hKey, hUID,
|
|
KEY_HANDLE)) == NULL)
|
|
{
|
|
if (GetLastError() == NTE_FAIL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_KEY);
|
|
}
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if (pMAC->dwBufLen + dwTmpLen <= CRYPT_BLKLEN)
|
|
{
|
|
memcpy(pMAC->Buffer+pMAC->dwBufLen, pbTmp, dwTmpLen);
|
|
pMAC->dwBufLen += dwTmpLen;
|
|
return NTF_SUCCEED;
|
|
}
|
|
|
|
memcpy(pMAC->Buffer+pMAC->dwBufLen, pbTmp,
|
|
(CRYPT_BLKLEN - pMAC->dwBufLen));
|
|
|
|
dwTmpLen -= (CRYPT_BLKLEN - pMAC->dwBufLen);
|
|
pbTmp += (CRYPT_BLKLEN - pMAC->dwBufLen);
|
|
|
|
pMAC->dwBufLen = CRYPT_BLKLEN;
|
|
|
|
switch (pTmpKey->Algid)
|
|
{
|
|
case CALG_RC2:
|
|
if (BlockEncrypt(RC2, pTmpKey, RC2_BLOCKLEN, FALSE,
|
|
pMAC->Buffer, &pMAC->dwBufLen,
|
|
CRYPT_BLKLEN) == NTF_FAILED)
|
|
{
|
|
return NTF_FAILED;
|
|
}
|
|
break;
|
|
|
|
case CALG_DES:
|
|
if (BlockEncrypt(des, pTmpKey, DES_BLOCKLEN, FALSE,
|
|
pMAC->Buffer, &pMAC->dwBufLen,
|
|
CRYPT_BLKLEN) == NTF_FAILED)
|
|
{
|
|
return NTF_FAILED;
|
|
}
|
|
}
|
|
|
|
pMAC->dwBufLen = 0;
|
|
|
|
dwBufSlop = dwTmpLen % CRYPT_BLKLEN;
|
|
if (dwBufSlop == 0)
|
|
{
|
|
dwBufSlop = CRYPT_BLKLEN;
|
|
}
|
|
|
|
if ((pbJunk = _nt_malloc(dwTmpLen)) == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
memcpy(pbJunk, pbTmp, dwTmpLen - dwBufSlop);
|
|
|
|
dwEncLen = dwTmpLen - dwBufSlop;
|
|
|
|
switch (pTmpKey->Algid)
|
|
{
|
|
case CALG_RC2:
|
|
if (BlockEncrypt(RC2, pTmpKey, RC2_BLOCKLEN, FALSE,
|
|
pbJunk, &dwEncLen,
|
|
dwTmpLen) == NTF_FAILED)
|
|
{
|
|
_nt_free(pbJunk, dwTmpLen);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
break;
|
|
case CALG_DES:
|
|
if (BlockEncrypt(des, pTmpKey, DES_BLOCKLEN, FALSE,
|
|
pbJunk, &dwEncLen,
|
|
dwTmpLen) == NTF_FAILED)
|
|
{
|
|
_nt_free(pbJunk, dwTmpLen);
|
|
return NTF_FAILED;
|
|
}
|
|
}
|
|
|
|
_nt_free(pbJunk, dwTmpLen);
|
|
|
|
memcpy(pMAC->Buffer, pbTmp + dwEncLen, dwBufSlop);
|
|
pMAC->dwBufLen = dwBufSlop;
|
|
|
|
return NTF_SUCCEED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CSP_USE_MD2
|
|
|
|
case CALG_MD2:
|
|
{
|
|
MD2_object *pMD2Hash;
|
|
|
|
pMD2Hash = (MD2_object *) pTmpHash->pHashData;
|
|
|
|
// make sure the hash is updatable
|
|
if (pMD2Hash->FinishFlag == TRUE)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
f = MD2Update(&pMD2Hash->MD, pbTmp, dwTmpLen);
|
|
|
|
if (f != 0)
|
|
{
|
|
SetLastError((DWORD) NTE_FAIL);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CSP_USE_MD4
|
|
|
|
case CALG_MD4:
|
|
{
|
|
MD4_object *pMD4Hash;
|
|
BYTE *ptmp;
|
|
|
|
pMD4Hash = (MD4_object *) pTmpHash->pHashData;
|
|
|
|
// make sure the hash is updatable
|
|
if (pMD4Hash->FinishFlag == TRUE)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// 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 *) pbTmp;
|
|
for (;;)
|
|
{
|
|
// check if there's plenty of room in the buffer
|
|
if (dwTmpLen < (MD4BLOCKSIZE - pMD4Hash->BufLen))
|
|
{
|
|
// just append to whatever's already
|
|
memcpy (pMD4Hash->Buf + pMD4Hash->BufLen, ptmp, dwTmpLen);
|
|
|
|
// set of the trailing buffer length field
|
|
pMD4Hash->BufLen += (BYTE)dwTmpLen;
|
|
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.
|
|
f = MDupdate(&pMD4Hash->MD, pMD4Hash->Buf,
|
|
MD4BYTESTOBITS(MD4BLOCKSIZE));
|
|
|
|
ASSERT(f == MD4_SUCCESS);
|
|
|
|
if (f != MD4_SUCCESS)
|
|
{
|
|
SetLastError((DWORD) NTE_FAIL);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// now it's empty.
|
|
pMD4Hash->BufLen = 0;
|
|
|
|
// we processed some bytes, so reflect that and try again
|
|
dwTmpLen -= BytePos;
|
|
ptmp += BytePos;
|
|
|
|
if (dwTmpLen == 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 == TRUE)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
MD5Update(pMD5Hash, pbTmp, dwTmpLen);
|
|
|
|
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 == TRUE)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
A_SHAUpdate(pSHAHash, (BYTE *) pbTmp, dwTmpLen);
|
|
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
default:
|
|
SetLastError((DWORD) NTE_BAD_ALGID);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
return NTF_SUCCEED;
|
|
|
|
}
|
|
|
|
/*
|
|
- 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 CPHashSessionKey(IN HCRYPTPROV hUID,
|
|
IN HCRYPTHASH hHash,
|
|
IN HCRYPTKEY hKey,
|
|
IN DWORD dwFlags)
|
|
{
|
|
PNTAGHashList pTmpHash;
|
|
PNTAGKeyList pTmpKey;
|
|
PNTAGUserList pTmpUser;
|
|
BSAFE_PUB_KEY *pBsafePubKey;
|
|
DWORD dwDataLen;
|
|
BYTE *pbData;
|
|
DWORD BytePos;
|
|
BOOL f;
|
|
BYTE *pScratch;
|
|
DWORD z;
|
|
|
|
if (dwFlags != 0)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_FLAGS);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// check the user identification
|
|
if ((pTmpUser = (PNTAGUserList) NTLCheckList (hUID, USER_HANDLE)) == NULL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_UID);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pTmpHash = (PNTAGHashList) NTLValidate(hHash, hUID,
|
|
HASH_HANDLE)) == NULL)
|
|
{
|
|
if (GetLastError() == NTE_FAIL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH);
|
|
}
|
|
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if (pTmpHash->HashFlags & HF_VALUE_SET)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pTmpKey = (PNTAGKeyList) NTLValidate((HNTAG)hKey, hUID, KEY_HANDLE))
|
|
== NULL)
|
|
{
|
|
if (GetLastError() == NTE_FAIL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_KEY);
|
|
}
|
|
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// Check if we should do an auto-inflate
|
|
if (pTmpKey->pData == NULL)
|
|
{
|
|
if (NTAG_FAILED(CPInflateKey(hUID, hKey, dwFlags)))
|
|
{
|
|
return NTF_FAILED;
|
|
}
|
|
}
|
|
|
|
dwDataLen = pTmpKey->cbKeyLen;
|
|
pbData = pTmpKey->pKeyValue;
|
|
|
|
if ((pScratch = (BYTE *)_nt_malloc(dwDataLen)) == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
// Reverse the session key bytes
|
|
for (z = 0; z < dwDataLen; ++z) pScratch[z] = pbData[dwDataLen - z - 1];
|
|
|
|
pbData = pScratch;
|
|
|
|
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 == TRUE)
|
|
{
|
|
_nt_free(pScratch, dwDataLen);
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
f = MD2Update(&pMD2Hash->MD, pbData, dwDataLen);
|
|
|
|
if (f != 0)
|
|
{
|
|
SetLastError((DWORD) NTE_FAIL);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CSP_USE_MD4
|
|
case CALG_MD4:
|
|
{
|
|
MD4_object *pMD4Hash;
|
|
|
|
pMD4Hash = (MD4_object *) pTmpHash->pHashData;
|
|
|
|
// make sure the hash is updatable
|
|
if (pMD4Hash->FinishFlag == TRUE)
|
|
{
|
|
_nt_free(pScratch, dwDataLen);
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
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.
|
|
f = MDupdate(&pMD4Hash->MD, pMD4Hash->Buf,
|
|
MD4BYTESTOBITS(MD4BLOCKSIZE));
|
|
|
|
if (f != MD4_SUCCESS)
|
|
{
|
|
_nt_free(pScratch, dwDataLen);
|
|
SetLastError((DWORD) NTE_FAIL);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// 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 == TRUE)
|
|
{
|
|
_nt_free(pScratch, dwDataLen);
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
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 == TRUE)
|
|
{
|
|
_nt_free(pScratch, dwDataLen);
|
|
SetLastError((DWORD) NTE_BAD_HASH_STATE);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
A_SHAUpdate(pSHAHash, (BYTE *) pbData, dwDataLen);
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
default:
|
|
_nt_free(pScratch, dwDataLen);
|
|
SetLastError((DWORD) NTE_BAD_ALGID);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
_nt_free(pScratch, dwDataLen);
|
|
|
|
return NTF_SUCCEED;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
- CPDestroyHash
|
|
-
|
|
* Purpose:
|
|
* Destory the hash object
|
|
*
|
|
*
|
|
* Parameters:
|
|
* IN hUID - Handle to the user identifcation
|
|
* IN hHash - Handle to hash object
|
|
*
|
|
* Returns:
|
|
*/
|
|
BOOL CPDestroyHash(IN HCRYPTPROV hUID,
|
|
IN HCRYPTHASH hHash)
|
|
{
|
|
PNTAGHashList pTmpHash;
|
|
|
|
// check the user identification
|
|
if (NTLCheckList (hUID, USER_HANDLE) == NULL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_UID);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
if ((pTmpHash = (PNTAGHashList) NTLValidate(hHash, hUID,
|
|
HASH_HANDLE)) == NULL)
|
|
{
|
|
// NTLValidate doesn't know what error to set
|
|
// so it set NTE_FAIL -- fix it up.
|
|
if (GetLastError() == NTE_FAIL)
|
|
{
|
|
SetLastError((DWORD) NTE_BAD_HASH);
|
|
}
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
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:
|
|
|
|
#endif
|
|
|
|
memnuke(pTmpHash->pHashData, pTmpHash->dwDataLen);
|
|
break;
|
|
|
|
default:
|
|
SetLastError((DWORD) NTE_BAD_ALGID);
|
|
return NTF_FAILED;
|
|
}
|
|
|
|
// Remove from internal list first so others can't get to it, then free.
|
|
NTLDelete(hHash);
|
|
_nt_free(pTmpHash->pHashData, pTmpHash->dwDataLen);
|
|
_nt_free(pTmpHash, sizeof(NTAGHashList));
|
|
|
|
return NTF_SUCCEED;
|
|
|
|
}
|