|
|
/////////////////////////////////////////////////////////////////////////////
// FILE : nt_key.c //
// DESCRIPTION : Crypto CP interfaces: //
// CPGenKey //
// CPDeriveKey //
// CPExportKey //
// CPImportKey //
// CPDestroyKey //
// CPGetUserKey //
// CPSetKeyParam //
// CPGetKeyParam //
// AUTHOR : //
// HISTORY : //
// Jan 25 1995 larrys Changed from Nametag //
// Feb 16 1995 larrys Fix problem for 944 build //
// Feb 21 1995 larrys Added SPECIAL_KEY //
// Feb 23 1995 larrys Changed NTag_SetLastError to SetLastError //
// Mar 08 1995 larrys Fixed a few problems //
// Mar 23 1995 larrys Added variable key length //
// Apr 7 1995 larrys Removed CryptConfigure //
// Apr 17 1995 larrys Added 1024 key gen //
// Apr 19 1995 larrys Changed CRYPT_EXCH_PUB to AT_KEYEXCHANGE //
// May 10 1995 larrys added private api calls //
// May 17 1995 larrys added key data for DES test //
// Jul 20 1995 larrys Changed export of PUBLICKEYBLOB //
// Jul 21 1995 larrys Fixed Export of AUTHENTICATEDBLOB //
// Aug 03 1995 larrys Allow CryptG(S)etKeyParam for Public keys & //
// Removed CPTranslate //
// Aug 10 1995 larrys Fixed a few problems in CryptGetKeyParam //
// Aug 11 1995 larrys Return no key for CryptGetUserKey //
// Aug 14 1995 larrys Removed key exchange stuff //
// Aug 17 1995 larrys Removed a error //
// Aug 18 1995 larrys Changed NTE_BAD_LEN to ERROR_MORE_DATA //
// Aug 30 1995 larrys Removed RETURNASHVALUE from CryptGetHashValue //
// Aug 31 1995 larrys Fixed CryptExportKey if pbData == NULL //
// Sep 05 1995 larrys Fixed bug # 30 //
// Sep 05 1995 larrys Fixed bug # 31 //
// Sep 11 1995 larrys Fixed bug # 34 //
// Sep 12 1995 larrys Removed 2 DWORDS from exported keys //
// Sep 14 1995 Jeffspel/ramas Merged STT onto CSP //
// Sep 18 1995 larrys Changed def KP_PERMISSIONS to 0xffffffff //
// Oct 02 1995 larrys Fixed bug 43 return error for importkey on hPubkey //
// Oct 03 1995 larrys Fixed bug 37 call InflateKey from SetKeyParam //
// Oct 03 1995 larrys Fixed bug 36, removed OFB from SetKeyParam //
// Oct 03 1995 larrys Fixed bug 38, check key type in SetKeyParam //
// Oct 13 1995 larrys Added CPG/setProv/HashParam //
// Oct 13 1995 larrys Added code for CryptSetHashValue //
// Oct 16 1995 larrys Changes for CryptGetHashParam //
// Oct 23 1995 larrys Added code for GetProvParam PP_CONTAINER //
// Oct 27 1995 rajeshk RandSeed Stuff added hUID to PKCS2Encrypt+ others //
// Nov 3 1995 larrys Merge changes for NT checkin //
// Nov 9 1995 larrys Bug fix 10686 //
// Nov 30 1995 larrys Bug fix //
// Dec 11 1995 larrys Added WIN96 password cache //
// Feb 29 1996 rajeshk Added Check for SetHashParam for HASHVALUE //
// May 15 1996 larrys Added private key export //
// May 28 1996 larrys Fix bug 88 //
// Jun 6 1996 a-johnb Added support for SSL 3.0 signatures //
// Aug 28 1996 mattt Changed enum to calculate size from #defined sizes //
// Sep 13 1996 mattt Compat w/RSABase 88-bit 0 salt, FIsLegalKey() //
// Sep 16 1996 mattt Added KP_KEYLEN ability //
// Sep 16 1996 jeffspel Added triple DES functionality //
// Oct 14 1996 jeffspel Changed GenRandoms to NewGenRandoms //
// Apr 29 1997 jeffspel Key storage ability GetProvParam, PStore support //
// Apr 29 1997 jeffspel Added EnumAlgsEx tp GetProvParam //
// May 23 1997 jeffspel Added provider type checking //
// Jul 15 1997 jeffspel Added ability to decrypt with large RC2 keys //
// Jul 28 1997 jeffspel Added ability to delete a persisted key //
// Sep 09 1997 jeffspel Added PP_KEYSET_TYPE to CPGetProvParam //
// Sep 12 1997 jeffspel Added Opaque blob support //
// May 4 2000 dbarlow Error code return cleanup //
// //
// Copyright (C) 1993 - 2000 Microsoft Corporation //
// All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "nt_rsa.h"
#include "nt_blobs.h"
#include "swnt_pk.h"
#include "mac.h"
#include "ntagimp1.h"
#include "tripldes.h"
#include "ntagum.h"
#include "randlib.h"
#ifdef CSP_USE_SSL3
#include "ssl3.h"
#endif
#include "protstor.h"
#include "sgccheck.h"
#include "aes.h"
extern CSP_STRINGS g_Strings;
#ifndef CSP_USE_AES
#define UnsupportedSymKey(pKey) ((CALG_RC4 != pKey->Algid) && \
(CALG_RC2 != pKey->Algid) && \ (CALG_DES != pKey->Algid) && \ (CALG_3DES != pKey->Algid) && \ (CALG_3DES_112 != pKey->Algid)) #else
#define UnsupportedSymKey(pKey) ((CALG_RC4 != pKey->Algid) && \
(CALG_RC2 != pKey->Algid) && \ (CALG_DES != pKey->Algid) && \ (CALG_3DES != pKey->Algid) && \ (CALG_3DES_112 != pKey->Algid) && \ (CALG_AES_128 != pKey->Algid) && \ (CALG_AES_192 != pKey->Algid) && \ (CALG_AES_256 != pKey->Algid)) #endif
#define NTAG_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\UserKeys"
#define NTAG_MACH_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\MachineKeys"
extern DWORD InflateKey( IN PNTAGKeyList pTmpKey);
/*static*/ DWORD CopyKey( IN PNTAGKeyList pOldKey, OUT PNTAGKeyList *ppNewKey);
extern DWORD SymEncrypt( IN PNTAGKeyList pKey, IN BOOL fFinal, IN OUT BYTE *pbData, IN OUT DWORD *pcbData, IN DWORD cbBuf);
extern DWORD SymDecrypt( IN PNTAGKeyList pKey, IN PNTAGHashList pHash, IN BOOL fFinal, IN OUT BYTE *pbData, IN OUT DWORD *pcbData);
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);
static BYTE rgbSymmetricKeyWrapIV[8] = {0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05};
//
// Set the permissions on the key
//
/*static*/ void SetInitialKeyPermissions( PNTAGKeyList pKey) { if (CRYPT_EXPORTABLE == pKey->Rights) { pKey->Permissions |= CRYPT_EXPORT; }
// UNDONE - set the appopropriate permission with the appropriate
// algorithm
pKey->Permissions |= CRYPT_ENCRYPT | CRYPT_DECRYPT| CRYPT_READ | CRYPT_WRITE | CRYPT_MAC; }
/* MakeNewKey
* * Helper routine for ImportKey, GenKey * * Allocate a new key record, fill in the data and copy in the key * bytes. */
DWORD MakeNewKey( ALG_ID aiKeyAlg, DWORD dwRights, DWORD dwKeyLen, HCRYPTPROV hUID, BYTE *pbKeyData, BOOL fUsePassedKeyBuffer, BOOL fPreserveExactKey, PNTAGKeyList *ppKeyList) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGKeyList pKey = NULL;
*ppKeyList = NULL;
// allocate space for the key record
pKey = (PNTAGKeyList)_nt_malloc(sizeof(NTAGKeyList)); if (NULL == pKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
if (!fUsePassedKeyBuffer) { pKey->pKeyValue = (BYTE *)_nt_malloc((size_t)dwKeyLen); if (NULL == pKey->pKeyValue) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } }
pKey->Algid = aiKeyAlg; pKey->Rights = dwRights; pKey->cbDataLen = 0; pKey->pData = NULL; pKey->hUID = hUID; memset(pKey->IV, 0, MAX_BLOCKLEN); memset(pKey->FeedBack, 0, MAX_BLOCKLEN); pKey->InProgress = FALSE; pKey->cbSaltLen = 0; pKey->Padding = PKCS5_PADDING; pKey->Mode = CRYPT_MODE_CBC; pKey->ModeBits = 0;
SetInitialKeyPermissions(pKey);
pKey->cbKeyLen = dwKeyLen; if (pbKeyData != NULL) { if (fUsePassedKeyBuffer) pKey->pKeyValue = pbKeyData; else memcpy(pKey->pKeyValue, pbKeyData, (size_t)dwKeyLen); }
// Handle special cases
switch (aiKeyAlg) { case CALG_RC2: // for RC2 set a default effective key length
pKey->EffectiveKeyLen = RC2_DEFAULT_EFFECTIVE_KEYLEN; pKey->dwBlockLen = RC2_BLOCKLEN; break; case CALG_DES: if (DES_KEYSIZE != pKey->cbKeyLen) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } if (!fPreserveExactKey) desparityonkey(pKey->pKeyValue, pKey->cbKeyLen); pKey->dwBlockLen = DES_BLOCKLEN; break; case CALG_3DES_112: if (DES_KEYSIZE * 2 != pKey->cbKeyLen) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } if (!fPreserveExactKey) desparityonkey(pKey->pKeyValue, pKey->cbKeyLen); pKey->dwBlockLen = DES_BLOCKLEN; break; case CALG_3DES: if (DES_KEYSIZE * 3 != pKey->cbKeyLen) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } if (!fPreserveExactKey) desparityonkey(pKey->pKeyValue, pKey->cbKeyLen); pKey->dwBlockLen = DES_BLOCKLEN; break; #ifdef CSP_USE_AES
case CALG_AES_128: pKey->dwBlockLen = CRYPT_AES128_BLKLEN; break; case CALG_AES_192: pKey->dwBlockLen = CRYPT_AES192_BLKLEN; break; case CALG_AES_256: pKey->dwBlockLen = CRYPT_AES256_BLKLEN; break; #endif
default: pKey->dwBlockLen = 0; }
*ppKeyList = pKey; return ERROR_SUCCESS;
ErrorExit: if (NULL != pKey) _nt_free (pKey, sizeof(NTAGKeyList)); return dwReturn; }
/* FreeNewKey
* * Use for cleanup on abort of key build operations. * */
void FreeNewKey( PNTAGKeyList pOldKey) { if (pOldKey->pKeyValue) _nt_free(pOldKey->pKeyValue, pOldKey->cbKeyLen); if (pOldKey->pData) _nt_free(pOldKey->pData, pOldKey->cbDataLen); _nt_free(pOldKey, sizeof(NTAGKeyList)); }
/* FIsLegalKeySize
* * Check that the length of the key is legal (essentially * complies with export). * */
BOOL FIsLegalKeySize( IN DWORD dwCspTypeId, IN ALG_ID Algid, IN DWORD cbKey, IN BOOL fRC2BigKeyOK, OUT BOOL *pfPubKey) { BOOL fRet = FALSE;
*pfPubKey = FALSE;
switch (Algid) { #ifdef CSP_USE_RC2
case CALG_RC2: if (!fRC2BigKeyOK) { if (!IsLegalLength(g_AlgTables[dwCspTypeId], Algid, cbKey * 8, NULL)) goto ErrorExit; } break; #endif
#ifdef CSP_USE_DES
case CALG_DES: if ((DES_KEYSIZE != cbKey) && ((DES_KEYSIZE - 1) != cbKey)) goto ErrorExit; break; #endif
#ifdef CSP_USE_3DES
case CALG_3DES_112: if ((DES2_KEYSIZE != cbKey) && ((DES2_KEYSIZE - 2) != cbKey)) goto ErrorExit; break; case CALG_3DES: if ((DES3_KEYSIZE != cbKey) && ((DES3_KEYSIZE - 3) != cbKey)) goto ErrorExit; break; #endif
case CALG_RSA_SIGN: case CALG_RSA_KEYX: *pfPubKey = TRUE; // Fall through intentionally.
default: if (!IsLegalLength(g_AlgTables[dwCspTypeId], Algid, cbKey * 8, NULL)) goto ErrorExit; }
fRet = TRUE;
ErrorExit: // not of regulation size
return fRet; }
#ifdef USE_SGC
/* FIsLegalSGCKeySize
* * Check that the length of the key is SGC legal (essentially * complies with export). * */
BOOL FIsLegalSGCKeySize( IN ALG_ID Algid, IN DWORD cbKey, IN BOOL fRC2BigKeyOK, IN BOOL fGenKey, OUT BOOL *pfPubKey) { BOOL fSts = FALSE;
if (!fGenKey) { if (!FIsLegalKeySize(POLICY_MS_SCHANNEL, Algid, cbKey, fRC2BigKeyOK, pfPubKey)) goto ErrorExit; } else { switch (Algid) { #ifdef CSP_USE_RC2
case CALG_RC2: if (!fRC2BigKeyOK) goto ErrorExit; break; #endif
#ifdef CSP_USE_SSL3
case CALG_SSL3_MASTER: case CALG_TLS1_MASTER: case CALG_PCT1_MASTER: case CALG_SSL2_MASTER: if (!FIsLegalKeySize(POLICY_MS_SCHANNEL, Algid, cbKey, fRC2BigKeyOK, pfPubKey)) goto ErrorExit; break; case CALG_SCHANNEL_MAC_KEY: break; #endif
case CALG_RSA_KEYX: if (!FIsLegalKeySize(POLICY_MS_SCHANNEL, Algid, cbKey, fRC2BigKeyOK, pfPubKey)) goto ErrorExit; break; default: goto ErrorExit; } }
fSts = TRUE;
ErrorExit: return fSts; } #endif
/* FIsLegalKey
* * Check that the length of the key is legal (essentially * complies with export). * */
BOOL FIsLegalKey( IN PNTAGUserList pTmpUser, IN PNTAGKeyList pKey, IN BOOL fRC2BigKeyOK) { BOOL fPubKey; BOOL fRet = FALSE;
if (pKey == NULL) goto ErrorExit;
#ifdef USE_SGC
// check if the provider is an SChannel provider and if so if the
// SGC flag is set then use the FIsLegalSGCKeySize function
if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && (0 != pTmpUser->dwSGCFlags)) { if (!FIsLegalSGCKeySize(pKey->Algid, pKey->cbKeyLen, fRC2BigKeyOK, FALSE, &fPubKey)) { goto ErrorExit; } } else #endif
{ // 4th parameter, dwFlags, is used for SGC Exch keys so just
// pass zero in this case
if (!FIsLegalKeySize(pTmpUser->dwCspTypeId, pKey->Algid, pKey->cbKeyLen, fRC2BigKeyOK, &fPubKey)) { goto ErrorExit; } }
fRet = TRUE;
ErrorExit: return fRet; }
/* FIsLegalImportSymKey
* * Verify that imported symmetric keys meet the size restrictions * of the CSP in use. In addition, require all DES-variant * keys to be of the full required size, including parity bits. */ BOOL FIsLegalImportSymKey( IN PNTAGUserList pTmpUser, IN PNTAGKeyList pKey, IN BOOL fRC2BigKeyOK) { BOOL fRet = FALSE;
switch (pKey->Algid) { #ifdef CSP_USE_RC2
case CALG_RC2: if (!fRC2BigKeyOK) { if (!IsLegalLength(g_AlgTables[pTmpUser->dwCspTypeId], pKey->Algid, pKey->cbKeyLen * 8, NULL)) goto ErrorExit; } break; #endif
#ifdef CSP_USE_DES
case CALG_DES: if (DES_KEYSIZE != pKey->cbKeyLen) goto ErrorExit; break; #endif
#ifdef CSP_USE_3DES
case CALG_3DES_112: if (DES2_KEYSIZE != pKey->cbKeyLen) goto ErrorExit; break; case CALG_3DES: if (DES3_KEYSIZE != pKey->cbKeyLen) goto ErrorExit; break; #endif
case CALG_RSA_SIGN: case CALG_RSA_KEYX: goto ErrorExit;
default: if (!IsLegalLength(g_AlgTables[pTmpUser->dwCspTypeId], pKey->Algid, pKey->cbKeyLen * 8, NULL)) goto ErrorExit; }
fRet = TRUE;
ErrorExit: return fRet; }
/*static*/ DWORD MakeKeyRSABaseCompatible( HCRYPTPROV hUID, HCRYPTKEY hKey) { CRYPT_DATA_BLOB sSaltData; BYTE rgbZeroSalt[11]; BOOL fSts;
ZeroMemory(rgbZeroSalt, 11);
sSaltData.pbData = rgbZeroSalt; sSaltData.cbData = sizeof(rgbZeroSalt); fSts = CPSetKeyParam(hUID, hKey, KP_SALT_EX, (PBYTE)&sSaltData, 0); if (!fSts) return GetLastError(); return ERROR_SUCCESS; }
typedef struct { DWORD magic; /* Should always be RSA2 */ DWORD bitlen; // bit size of key
DWORD pubexp; // public exponent
} EXPORT_PRV_KEY, FAR *PEXPORT_PRV_KEY;
/* GetLengthOfPrivateKeyForExport
* * Get the length of the private key * blob from the public key. * */
/*static*/ void GetLengthOfPrivateKeyForExport( IN BSAFE_PUB_KEY *pPubKey, OUT PDWORD pcbBlob) { DWORD cbHalfModLen;
cbHalfModLen = (pPubKey->bitlen + 15) / 16; *pcbBlob = sizeof(EXPORT_PRV_KEY) + 9 * cbHalfModLen; }
/* PreparePrivateKeyForExport
* * Massage the key from the registry * into an exportable format. * */
/*static*/ BOOL PreparePrivateKeyForExport( IN BSAFE_PRV_KEY *pPrvKey, OUT PBYTE pbBlob, IN OUT PDWORD pcbBlob) { PEXPORT_PRV_KEY pExportKey; DWORD cbHalfModLen; DWORD cbBlobLen; DWORD cbTmpLen; DWORD cbHalfTmpLen; PBYTE pbIn; PBYTE pbOut;
cbHalfModLen = (pPrvKey->bitlen + 15) / 16; cbBlobLen = sizeof(EXPORT_PRV_KEY) + 9 * cbHalfModLen;
// figure out the number of overflow bytes which are in the private
// key structure
cbTmpLen = (sizeof(DWORD) * 2) - (((pPrvKey->bitlen + 7) / 8) % (sizeof(DWORD) * 2)); if ((sizeof(DWORD) * 2) != cbTmpLen) cbTmpLen += sizeof(DWORD) * 2; cbHalfTmpLen = cbTmpLen / 2;
if (NULL == pbBlob) { *pcbBlob = cbBlobLen; return TRUE; }
if (*pcbBlob < cbBlobLen) { *pcbBlob = cbBlobLen; return FALSE; }
// take most of the header info
pExportKey = (PEXPORT_PRV_KEY)pbBlob; pExportKey->magic = pPrvKey->magic; pExportKey->bitlen = pPrvKey->bitlen; pExportKey->pubexp = pPrvKey->pubexp;
pbIn = (PBYTE)pPrvKey + sizeof(BSAFE_PRV_KEY); pbOut = pbBlob + sizeof(EXPORT_PRV_KEY);
// copy all the private key info
CopyMemory(pbOut, pbIn, pExportKey->bitlen / 8); pbIn += pExportKey->bitlen / 8 + cbTmpLen; pbOut += pExportKey->bitlen / 8; CopyMemory(pbOut, pbIn, cbHalfModLen); pbIn += cbHalfModLen + cbHalfTmpLen; pbOut += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbIn += cbHalfModLen + cbHalfTmpLen; pbOut += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbIn += cbHalfModLen + cbHalfTmpLen; pbOut += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbIn += cbHalfModLen + cbHalfTmpLen; pbOut += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbIn += cbHalfModLen + cbHalfTmpLen; pbOut += cbHalfModLen; CopyMemory(pbOut, pbIn, pExportKey->bitlen / 8);
*pcbBlob = cbBlobLen; return TRUE; }
/* PreparePrivateKeyForImport
* * Massage the incoming into a form acceptable for * the registry. * */
/*static*/ BOOL PreparePrivateKeyForImport( IN PBYTE pbBlob, OUT BSAFE_PRV_KEY *pPrvKey, IN OUT PDWORD pPrvKeyLen, OUT BSAFE_PUB_KEY *pPubKey, IN OUT PDWORD pPubKeyLen) { PEXPORT_PRV_KEY pExportKey = (PEXPORT_PRV_KEY)pbBlob; DWORD cbHalfModLen; DWORD cbPub; DWORD cbPrv; PBYTE pbIn; PBYTE pbOut; DWORD cbTmpLen; DWORD cbHalfTmpLen;
if (RSA2 != pExportKey->magic) return FALSE;
// figure out the number of overflow bytes which are in the private
// key structure
cbTmpLen = (sizeof(DWORD) * 2) - (((pExportKey->bitlen + 7) / 8) % (sizeof(DWORD) * 2)); if ((sizeof(DWORD) * 2) != cbTmpLen) cbTmpLen += sizeof(DWORD) * 2; cbHalfTmpLen = cbTmpLen / 2; cbHalfModLen = (pExportKey->bitlen + 15) / 16;
cbPub = sizeof(BSAFE_PUB_KEY) + (pExportKey->bitlen / 8) + cbTmpLen; cbPrv = sizeof(BSAFE_PRV_KEY) + (cbHalfModLen + cbHalfTmpLen) * 10; if ((NULL == pPrvKey) || (NULL == pPubKey)) { *pPubKeyLen = cbPub; *pPrvKeyLen = cbPrv; return TRUE; }
if ((*pPubKeyLen < cbPub) || (*pPrvKeyLen < cbPrv)) { *pPubKeyLen = cbPub; *pPrvKeyLen = cbPrv; return FALSE; }
// form the public key
ZeroMemory(pPubKey, *pPubKeyLen); pPubKey->magic = RSA1; pPubKey->bitlen = pExportKey->bitlen; pPubKey->keylen = (pExportKey->bitlen / 8) + cbTmpLen; pPubKey->datalen = (pExportKey->bitlen+7)/8 - 1; pPubKey->pubexp = pExportKey->pubexp;
pbIn = pbBlob + sizeof(EXPORT_PRV_KEY); pbOut = (PBYTE)pPubKey + sizeof(BSAFE_PUB_KEY);
CopyMemory(pbOut, pbIn, pExportKey->bitlen / 8);
// form the private key
ZeroMemory(pPrvKey, *pPrvKeyLen); pPrvKey->magic = pExportKey->magic; pPrvKey->keylen = pPubKey->keylen; pPrvKey->bitlen = pExportKey->bitlen; pPrvKey->datalen = pPubKey->datalen; pPrvKey->pubexp = pExportKey->pubexp;
pbOut = (PBYTE)pPrvKey + sizeof(BSAFE_PRV_KEY);
CopyMemory(pbOut, pbIn, pExportKey->bitlen / 8); pbOut += pExportKey->bitlen / 8 + cbTmpLen; pbIn += pExportKey->bitlen / 8; CopyMemory(pbOut, pbIn, cbHalfModLen); pbOut += cbHalfModLen + cbHalfTmpLen; pbIn += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbOut += cbHalfModLen + cbHalfTmpLen; pbIn += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbOut += cbHalfModLen + cbHalfTmpLen; pbIn += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbOut += cbHalfModLen + cbHalfTmpLen; pbIn += cbHalfModLen; CopyMemory(pbOut, pbIn, cbHalfModLen); pbOut += cbHalfModLen + cbHalfTmpLen; pbIn += cbHalfModLen; CopyMemory(pbOut, pbIn, pExportKey->bitlen / 8);
*pPubKeyLen = cbPub; *pPrvKeyLen = cbPrv;
return TRUE; }
/*static*/ BOOL ValidKeyAlgid( PNTAGUserList pTmpUser, ALG_ID Algid) { if (ALG_CLASS_HASH == GET_ALG_CLASS(Algid)) return FALSE; return IsLegalAlgorithm(g_AlgTables[pTmpUser->dwCspTypeId], Algid, NULL); }
#ifdef USE_SGC
/*
- GetSGCDefaultKeyLength - * Purpose: * Returns the default key size in pcbKey. * * Parameters: * IN Algid - For the key to be created * OUT pcbKey - Size of the key in bytes to generate * OUT pfPubKey- TRUE if the Algid is a pub key * * Returns: TRUE on success, FALSE on failure. */
/*static*/ BOOL GetSGCDefaultKeyLength( IN ALG_ID Algid, OUT DWORD *pcbKey, OUT BOOL *pfPubKey) { BOOL fRet = FALSE;
*pfPubKey = FALSE;
// determine which crypt algorithm is to be used
switch (Algid) { #ifdef CSP_USE_SSL3
case CALG_SSL3_MASTER: case CALG_TLS1_MASTER: *pcbKey = SSL3_MASTER_KEYSIZE; break;
case CALG_PCT1_MASTER: *pcbKey = PCT1_MASTER_KEYSIZE; break;
case CALG_SSL2_MASTER: *pcbKey = SSL2_MASTER_KEYSIZE; break; #endif
case CALG_RSA_KEYX: *pcbKey = SGC_RSA_DEF_EXCH_MODLEN; *pfPubKey = TRUE; break;
default: goto ErrorExit; }
fRet = TRUE;
ErrorExit: return fRet; } #endif
/*
- GetDefaultKeyLength - * Purpose: * Returns the default key size in pcbKey. * * Parameters: * IN pTmpUser- The context info * IN Algid - For the key to be created * OUT pcbKey - Size of the key in bytes to generate * OUT pfPubKey- TRUE if the Algid is a pub key * * Returns: TRUE on success, FALSE on failure. */
/*static*/ BOOL GetDefaultKeyLength( IN PNTAGUserList pTmpUser, IN ALG_ID Algid, OUT DWORD *pcbKey, OUT BOOL *pfPubKey) { BOOL fRet = FALSE; DWORD cbits;
*pfPubKey = FALSE;
// determine which crypt algorithm is to be used
switch (Algid) { #ifdef CSP_USE_SSL3
case CALG_SSL3_MASTER: case CALG_TLS1_MASTER: *pcbKey = SSL3_MASTER_KEYSIZE; break;
case CALG_PCT1_MASTER: *pcbKey = PCT1_MASTER_KEYSIZE; break;
case CALG_SSL2_MASTER: *pcbKey = SSL2_MASTER_KEYSIZE; break; #endif
case CALG_RSA_KEYX: case CALG_RSA_SIGN: *pfPubKey = TRUE; // Fall through intentionally.
default: if (!GetDefaultLength(g_AlgTables[pTmpUser->dwCspTypeId], Algid, NULL, &cbits)) goto ErrorExit; *pcbKey = cbits / 8; }
fRet = TRUE;
ErrorExit: return fRet; }
/*
- CheckKeyLength - * Purpose: * Checks the settable key length and if it is OK then * returns that as the size of key to use (pcbKey). If * no key length is in dwFlags then the default key size * is returned (pcbKey). If a settable key size is * specified but is not legal then a failure occurs. * * Parameters: * IN Algid - For the key to be created * IN dwFlags - Flag value with possible key size * OUT pcbKey - Size of the key in bytes to generate * OUT pfPubKey- TRUE if the Algid is a pub key * * Returns: A DWORD status code. */
/*static*/ DWORD CheckKeyLength( IN PNTAGUserList pTmpUser, IN ALG_ID Algid, IN DWORD dwFlags, OUT DWORD *pcbKey, OUT BOOL *pfPubKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD cBits; DWORD cbKey = 0;
cBits = dwFlags >> 16; if (cBits) { // settable key sizes must be divisible by 8 (by bytes)
if (0 != (cBits % 8)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check if requested size is legal
cbKey = cBits / 8; #ifdef USE_SGC
if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && (0 != pTmpUser->dwSGCFlags)) { if (!FIsLegalSGCKeySize(Algid, cbKey, FALSE, TRUE, pfPubKey)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } } else #endif
{ if (!FIsLegalKeySize(pTmpUser->dwCspTypeId, Algid, cbKey, FALSE, pfPubKey)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } } *pcbKey = cbKey; } else { #ifdef USE_SGC
if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && (0 != pTmpUser->dwSGCFlags)) { if (!GetSGCDefaultKeyLength(Algid, pcbKey, pfPubKey)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } } else #endif
{ if (!GetDefaultKeyLength(pTmpUser, Algid, pcbKey, pfPubKey)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } } }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
#ifdef USE_SGC
/*
- CheckSGCSimpleForExport - * Purpose: * Check if the SGC key values in the context against the * passed in values to see if an simple blob export with * this key is allowed. * * * Parameters: * IN hUID - Handle to a CSP * IN Algid - Algorithm identifier * IN dwFlags - Flags values * OUT phKey - Handle to a generated key * * Returns: */
/*static*/ BOOL CheckSGCSimpleForExport( IN PNTAGUserList pTmpUser, IN BSAFE_PUB_KEY *pBsafePubKey) { BOOL fRet = FALSE; BYTE *pb;
pb = ((BYTE*)pBsafePubKey) + sizeof(BSAFE_PUB_KEY); if (((pBsafePubKey->bitlen / 8) != pTmpUser->cbSGCKeyMod) || (pBsafePubKey->pubexp != pTmpUser->dwSGCKeyExpo) || (0 != memcmp(pb, pTmpUser->pbSGCKeyMod, pTmpUser->cbSGCKeyMod))) { goto ErrorExit; }
fRet = TRUE;
ErrorExit: return fRet; } #endif
/*
- CPGenKey - * Purpose: * Generate cryptographic keys * * * Parameters: * IN hUID - Handle to a CSP * IN Algid - Algorithm identifier * IN dwFlags - Flags values * OUT phKey - Handle to a generated key * * Returns: */
BOOL WINAPI CPGenKey( IN HCRYPTPROV hUID, IN ALG_ID Algid, IN DWORD dwFlags, OUT HCRYPTKEY * phKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; PNTAGKeyList pTmpKey = NULL; DWORD dwRights = 0; BYTE rgbRandom[MAX_KEY_SIZE]; int localAlgid; DWORD cbKey; BOOL fPubKey = FALSE; BOOL fRet; DWORD dwSts;
EntryPoint if ((dwFlags & ~(CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED | CRYPT_CREATE_SALT | CRYPT_NO_SALT | KEY_LENGTH_MASK | CRYPT_SGCKEY | CRYPT_ARCHIVABLE)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
switch (Algid) { case AT_KEYEXCHANGE: localAlgid = CALG_RSA_KEYX; break;
case AT_SIGNATURE: localAlgid = CALG_RSA_SIGN; break;
default: if (0 != (dwFlags & CRYPT_ARCHIVABLE)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } localAlgid = Algid; break; }
pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if ((CRYPT_USER_PROTECTED & dwFlags) && (CRYPT_VERIFYCONTEXT & pTmpUser->Rights)) { dwReturn = (DWORD)NTE_SILENT_CONTEXT; goto ErrorExit; }
if (!ValidKeyAlgid(pTmpUser, localAlgid)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
// check if the size of the key is set in the dwFlags parameter
dwSts = CheckKeyLength(pTmpUser, localAlgid, dwFlags, &cbKey, &fPubKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
if (fPubKey) { dwSts = ReGenKey(hUID, dwFlags, (localAlgid == CALG_RSA_KEYX) ? NTPK_USE_EXCH : NTPK_USE_SIG, phKey, cbKey * 8); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } else { // Force the full key lengths on DES algorithms.
if (CALG_DES == localAlgid) cbKey = DES_KEYSIZE; else if (CALG_3DES_112 == localAlgid) cbKey = DES2_KEYSIZE; else if (CALG_3DES == localAlgid) cbKey = DES3_KEYSIZE;
// generate the random key
dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver, &pTmpUser->ContInfo.pbRandom, &pTmpUser->ContInfo.ContLens.cbRandom, rgbRandom, cbKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_FAIL
goto ErrorExit; }
if ((CALG_DES == localAlgid) || (CALG_3DES_112 == localAlgid) || (CALG_3DES == localAlgid)) { if (dwFlags & CRYPT_CREATE_SALT) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } } #ifdef CSP_USE_SSL3
else if (CALG_SSL3_MASTER == localAlgid) { // set the first byte to 0x03 and the second to 0x00
rgbRandom[0] = 0x03; rgbRandom[1] = 0x00; } else if (CALG_TLS1_MASTER == localAlgid) { // set the first byte to 0x03 and the second to 0x01
rgbRandom[0] = 0x03; rgbRandom[1] = 0x01; } #endif
// check if the key is CRYPT_EXPORTABLE
if (dwFlags & CRYPT_EXPORTABLE) dwRights = CRYPT_EXPORTABLE;
dwSts = MakeNewKey(localAlgid, dwRights, cbKey, hUID, rgbRandom, FALSE, FALSE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
if (dwFlags & CRYPT_CREATE_SALT) { if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) || (POLICY_MS_STRONG == pTmpUser->dwCspTypeId)) { pTmpKey->cbSaltLen = DEFAULT_WEAK_SALT_LENGTH; } else { pTmpKey->cbSaltLen = DEFAULT_STRONG_SALT_LENGTH; }
dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver, &pTmpUser->ContInfo.pbRandom, &pTmpUser->ContInfo.ContLens.cbRandom, pTmpKey->rgbSalt, pTmpKey->cbSaltLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_FAIL
goto ErrorExit; } }
dwSts = NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// if 40bit key + no mention of salt, set zeroized salt for RSABase compatibility
if ((5 == cbKey) && (!(dwFlags & CRYPT_NO_SALT)) && (!(dwFlags & CRYPT_CREATE_SALT)) && (CALG_SSL3_MASTER != Algid) && (CALG_TLS1_MASTER != Algid) && (CALG_PCT1_MASTER != Algid) && (CALG_SSL2_MASTER != Algid)) { dwSts = MakeKeyRSABaseCompatible(hUID, *phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) { if (pTmpKey) FreeNewKey(pTmpKey); SetLastError(dwReturn); } return fRet; }
/*
- CPDeriveKey - * Purpose: * Derive cryptographic keys from base data * * * Parameters: * IN hUID - Handle to a CSP * IN Algid - Algorithm identifier * IN hBaseData - Handle to hash of base data * IN dwFlags - Flags values * OUT phKey - Handle to a generated key * * Returns: */
BOOL WINAPI CPDeriveKey( IN HCRYPTPROV hUID, IN ALG_ID Algid, IN HCRYPTHASH hBaseData, IN DWORD dwFlags, OUT HCRYPTKEY * phKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser = NULL; PNTAGKeyList pTmpKey = NULL; DWORD dwRights = 0; BYTE rgbRandom[MAX_KEY_SIZE]; BYTE rgbBaseVal[MAX_KEY_SIZE]; HCRYPTHASH h1 = 0; HCRYPTHASH h2 = 0; BYTE rgbBuff1[64]; BYTE rgbBuff2[64]; BYTE rgbHash1[NT_HASH_BYTES]; BYTE rgbHash2[NT_HASH_BYTES]; DWORD cb1; DWORD cb2; DWORD i; PNTAGHashList pTmpHash; DWORD temp; BOOL fPubKey = FALSE; DWORD cbKey; BOOL fRet; DWORD dwSts;
EntryPoint if ((dwFlags & ~(CRYPT_EXPORTABLE | CRYPT_CREATE_SALT | CRYPT_NO_SALT | CRYPT_SERVER | KEY_LENGTH_MASK)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if (!ValidKeyAlgid(pTmpUser, Algid)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
dwSts = NTLValidate(hBaseData, 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; }
#ifdef CSP_USE_SSL3
// if the hash is for secure channel usage then go to that derive function
if (CALG_SCHANNEL_MASTER_HASH == pTmpHash->Algid) { dwReturn = SecureChannelDeriveKey(pTmpUser, pTmpHash, Algid, dwFlags, phKey); goto ErrorExit; } #endif // CSP_USE_SSL3
// check if the size of the key is set in the dwFlags parameter
dwSts = CheckKeyLength(pTmpUser, Algid, dwFlags, &cbKey, &fPubKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// Force the full key lengths on DES algorithms.
if (CALG_DES == Algid) cbKey = DES_KEYSIZE; else if (CALG_3DES_112 == Algid) cbKey = DES2_KEYSIZE; else if (CALG_3DES == Algid) cbKey = DES3_KEYSIZE;
if (fPubKey) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
if (pTmpHash->HashFlags & HF_VALUE_SET) { dwReturn = (DWORD)NTE_BAD_HASH; goto ErrorExit; }
memset(rgbBaseVal, 0, MAX_KEY_SIZE); temp = MAX_KEY_SIZE; if (!CPGetHashParam(hUID, hBaseData, HP_HASHVAL, rgbBaseVal, &temp, 0)) { dwReturn = GetLastError(); goto ErrorExit; }
#ifdef CSP_USE_3DES
if (CALG_3DES == Algid) { // the hash value is not long enough so we must expand it
if (!CPCreateHash(hUID, pTmpHash->Algid, 0, 0, &h1)) { dwReturn = GetLastError(); goto ErrorExit; } if (!CPCreateHash(hUID, pTmpHash->Algid, 0, 0, &h2)) { dwReturn = GetLastError(); goto ErrorExit; }
// set up the two buffers to be hashed
memset(rgbBuff1, 0x36, sizeof(rgbBuff1)); memset(rgbBuff2, 0x5C, sizeof(rgbBuff2)); for (i=0;i<temp;i++) { rgbBuff1[i] ^= rgbBaseVal[i]; rgbBuff2[i] ^= rgbBaseVal[i]; }
// hash the two buffers
if (!CPHashData(hUID, h1, rgbBuff1, sizeof(rgbBuff1), 0)) { dwReturn = GetLastError(); goto ErrorExit; } if (!CPHashData(hUID, h2, rgbBuff2, sizeof(rgbBuff2), 0)) { dwReturn = GetLastError(); goto ErrorExit; }
// finish the hashes and copy them into BaseVal
memset(rgbHash1, 0, sizeof(rgbHash1)); cb1 = sizeof(rgbHash1); if (!CPGetHashParam(hUID, h1, HP_HASHVAL, rgbHash1, &cb1, 0)) { dwReturn = GetLastError(); goto ErrorExit; } memcpy(rgbBaseVal, rgbHash1, cb1);
memset(rgbHash2, 0, sizeof(rgbHash2)); cb2 = sizeof(rgbHash2); if (!CPGetHashParam(hUID, h2, HP_HASHVAL, rgbHash2, &cb2, 0)) { dwReturn = GetLastError(); goto ErrorExit; } memcpy(rgbBaseVal + cb1, rgbHash2, cb2); } #endif
memcpy(rgbRandom, rgbBaseVal, cbKey);
// check if the key is CRYPT_EXPORTABLE
if (dwFlags & CRYPT_EXPORTABLE) dwRights = CRYPT_EXPORTABLE;
dwSts = MakeNewKey(Algid, dwRights, cbKey, hUID, rgbRandom, FALSE, FALSE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
if (dwFlags & CRYPT_CREATE_SALT) { if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) || (POLICY_MS_STRONG == pTmpUser->dwCspTypeId)) { pTmpKey->cbSaltLen = DEFAULT_WEAK_SALT_LENGTH; } else { pTmpKey->cbSaltLen = DEFAULT_STRONG_SALT_LENGTH; }
memcpy(pTmpKey->rgbSalt, rgbBaseVal+cbKey, pTmpKey->cbSaltLen); }
dwSts = NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// if 40bit key + no mention of salt, set zeroized salt for RSABase
// compatibility
if ((5 == cbKey) && (!(dwFlags & CRYPT_NO_SALT)) && (!(dwFlags & CRYPT_CREATE_SALT))) { dwSts = MakeKeyRSABaseCompatible(hUID, *phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (pTmpUser && h1) CPDestroyHash(hUID, h1); if (pTmpUser && h2) CPDestroyHash(hUID, h2); if (!fRet) { if (NULL != pTmpKey) FreeNewKey(pTmpKey); SetLastError(dwReturn); } return fRet; }
/*static*/ DWORD ExportOpaqueBlob( PNTAGKeyList pKey, BYTE *pbData, DWORD *pcbData) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD cb = 0; PNTAGPackedKeyList pPackedKey;
// make sure the key is a symmetric key
if ((CALG_RSA_SIGN == pKey->Algid) || (CALG_RSA_KEYX == pKey->Algid)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// calculate the length of the blob
cb = sizeof(BLOBHEADER) + sizeof(NTAGPackedKeyList) + pKey->cbKeyLen + pKey->cbDataLen;
if (pbData == NULL || *pcbData < cb) { *pcbData = cb; if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
// set up the blob
pPackedKey = (PNTAGPackedKeyList)(pbData + sizeof(BLOBHEADER));
memset(pPackedKey, 0, sizeof(NTAGPackedKeyList));
pPackedKey->Algid = pKey->Algid; pPackedKey->Rights = pKey->Rights; memcpy(pPackedKey->IV, pKey->IV, sizeof(pKey->IV)); memcpy(pPackedKey->FeedBack, pKey->FeedBack, sizeof(pKey->FeedBack)); pPackedKey->InProgress = pKey->InProgress; pPackedKey->cbSaltLen = pKey->cbSaltLen; memcpy(pPackedKey->rgbSalt, pKey->rgbSalt, sizeof(pKey->rgbSalt)); pPackedKey->Padding = pKey->Padding; pPackedKey->Mode = pKey->Mode; pPackedKey->ModeBits = pKey->ModeBits; pPackedKey->Permissions = pKey->Permissions; pPackedKey->EffectiveKeyLen = pKey->EffectiveKeyLen; pPackedKey->dwBlockLen = pKey->dwBlockLen;
if (pKey->pKeyValue) { memcpy((PBYTE)pPackedKey + sizeof(NTAGPackedKeyList), pKey->pKeyValue, pKey->cbKeyLen);
pPackedKey->cbKeyLen = pKey->cbKeyLen; }
if(pKey->pData) { memcpy((PBYTE)pPackedKey + sizeof(NTAGPackedKeyList) + pPackedKey->cbKeyLen, pKey->pData, pKey->cbDataLen);
pPackedKey->cbDataLen = pKey->cbDataLen; }
*pcbData = cb; dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
/*
- GetRC4KeyForSymWrap - * Purpose: * RC4 or more precisely stream ciphers are not supported by the CMS spec * on symmetric key wrapping so we had to do something proprietary since * we want to support RC4 for applications other than SMIME * * * Parameters: * IN pTmpUser - Pointer to the context * IN pbSalt - Pointer to the 8 byte salt buffer * IN pKey - Pointer to the orignial key * OUT ppNewKey - Pointer to a pointer to the new key */
/*static*/ DWORD GetRC4KeyForSymWrap( IN BYTE *pbSalt, IN PNTAGKeyList pKey, OUT PNTAGKeyList *ppNewKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD dwSts;
// duplicate the key
dwSts = CopyKey(pKey, ppNewKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// set the value as salt + current salt
(*ppNewKey)->cbSaltLen += 8; memcpy((*ppNewKey)->rgbSalt + ((*ppNewKey)->cbSaltLen - 8), pbSalt, 8); dwSts = InflateKey(*ppNewKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
/*
- GetSymmetricKeyChecksum - * Purpose: * Calculates the checksum for a symmetric key which is to be * wrapped with another symmetric key. This should meet the * CMS specification * * * Parameters: * IN pKey - Pointer to the key * OUT pbChecksum - Pointer to the 8 byte checksum */
/*static*/ void GetSymmetricKeyChecksum( IN BYTE *pbKey, IN DWORD cbKey, OUT BYTE *pbChecksum) { A_SHA_CTX SHACtx; BYTE rgb[A_SHA_DIGEST_LEN];
A_SHAInit(&SHACtx); A_SHAUpdate(&SHACtx, pbKey, cbKey); A_SHAFinal(&SHACtx, rgb);
memcpy(pbChecksum, rgb, 8); }
/*
- WrapSymKey - * Purpose: * Wrap a symmetric key with another symmetric key. This should * meet the CMS specification for symmetric key wrapping. * * Parameters: * IN pTmpUser - Pointer to the user context * IN pKey - Pointer to the key to be wrapped * IN pWrapKey - Pointer to the key to be used for wrapping * IN OUT pbBlob - Pointer to the resulting blob (may be NULL * to get the length) * IN OUT pcbBlob - Pointer to the length of the blob buffer */
/*static*/ DWORD WrapSymKey( IN PNTAGUserList pTmpUser, IN PNTAGKeyList pKey, IN PNTAGKeyList pWrapKey, IN OUT BYTE *pbBlob, IN OUT DWORD *pcbBlob) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD cb = 0; DWORD cbIndex = 0; DWORD cbPad = 0; BLOBHEADER *pBlobHdr; ALG_ID *pAlgid; BYTE rgbTmp1[49]; // 1 length + 8 padding + 8 checksum + 8 IV + 24 max key
BYTE rgbTmp2[49]; // 1 length + 8 padding + 8 checksum + 8 IV + 24 max key
BYTE rgbIV[8]; PNTAGKeyList pLocalWrapKey = NULL; BOOL fAlloc = FALSE; DWORD i; DWORD dwSts;
memset(rgbTmp1, 0, sizeof(rgbTmp1)); memset(rgbTmp2, 0, sizeof(rgbTmp2)); memset(rgbIV, 0, sizeof(rgbIV));
// both keys must be supported symmetric keys
if (UnsupportedSymKey(pKey) || UnsupportedSymKey(pWrapKey)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
#ifdef CSP_USE_AES
// For now, punt on supporting AES algs in this scenario
if (CALG_AES_128 == pWrapKey->Algid || CALG_AES_192 == pWrapKey->Algid || CALG_AES_256 == pWrapKey->Algid || CALG_AES_128 == pKey->Algid || CALG_AES_192 == pKey->Algid || CALG_AES_256 == pKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } #endif
if ((!FIsLegalKey(pTmpUser, pKey, FALSE)) || (!FIsLegalKey(pTmpUser, pWrapKey, FALSE))) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// Check if we should do an auto-inflate
if (pWrapKey->pData == NULL) { dwSts = InflateKey(pWrapKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
// calculate how long the encrypted data is going to be.
if ((CALG_RC4 == pKey->Algid) || (CALG_RC2 == pKey->Algid)) // variable key lengths
{ // 1 byte for length, up to 8 bytes for pad and 8 bytes
// for the checksum and 8 bytes for the IV
cbPad = 8 - ((pKey->cbKeyLen + 1) % 8); cb += pKey->cbKeyLen + 9 + cbPad + 8;
// place the length in the buffer
rgbTmp1[0] = (BYTE)pKey->cbKeyLen; cbIndex += 1; } else { // up to 8 bytes for salt and 8 bytes for the checksum and 8 bytes
// for the IV
cb += pKey->cbKeyLen + 16; }
// check if just looking for a length
if (NULL == pbBlob) { *pcbBlob = cb + sizeof(BLOBHEADER) + sizeof(ALG_ID); dwReturn = ERROR_SUCCESS; goto ErrorExit; } else if (*pcbBlob < (cb + sizeof(BLOBHEADER) + sizeof(ALG_ID))) { *pcbBlob = cb + sizeof(BLOBHEADER) + sizeof(ALG_ID); dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
// copy the key data
memcpy(rgbTmp1 + cbIndex, pKey->pKeyValue, pKey->cbKeyLen); cbIndex += pKey->cbKeyLen;
// generate random pad
if (cbPad) { dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver, &pTmpUser->ContInfo.pbRandom, &pTmpUser->ContInfo.ContLens.cbRandom, rgbTmp1 + cbIndex, cbPad); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } cbIndex += cbPad; }
// get the checksum
GetSymmetricKeyChecksum(rgbTmp1, cbIndex, rgbTmp1 + cbIndex); cbIndex += 8;
dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver, &pTmpUser->ContInfo.pbRandom, &pTmpUser->ContInfo.ContLens.cbRandom, rgbIV, 8); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// set the IV if the algorithm is not RC4
if (CALG_RC4 != pWrapKey->Algid) { memcpy(pWrapKey->IV, rgbIV, 8); pWrapKey->InProgress = FALSE; pLocalWrapKey = pWrapKey; } else { // RC4 ()or more precisely stream ciphers) are not supported by the
// CMS spec for symmetric key wrapping. Therefore we had to do
// something proprietary to support RC4 for applications other
// than SMIME.
dwSts = GetRC4KeyForSymWrap(rgbIV, pWrapKey, &pLocalWrapKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } fAlloc = TRUE; }
// encrypt the key blob data
dwSts = SymEncrypt(pLocalWrapKey, FALSE, rgbTmp1, &cbIndex, cbIndex); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// concatenate the initial ciphertext with the IV
memcpy(rgbTmp2, rgbIV, 8); memcpy(rgbTmp2 + 8, rgbTmp1, cbIndex); cbIndex += 8;
// byte reverse the ciphertext + IV buffer
for (i = 0; i < cbIndex; i++) rgbTmp1[i] = rgbTmp2[cbIndex - (i + 1)];
// encrypt the key blob data again with the hardcoded IV
if (CALG_RC4 != pWrapKey->Algid) { memcpy(pWrapKey->IV, rgbSymmetricKeyWrapIV, 8); pWrapKey->InProgress = FALSE; } else { if (fAlloc && pLocalWrapKey) { FreeNewKey(pLocalWrapKey); pLocalWrapKey = NULL; fAlloc = FALSE; }
// RC4 (or more precisely stream ciphers) are not supported by the
// CMS spec for symmetric key wrapping. Therefore we had to do
// something proprietary to support RC4 for applications other
// than SMIME
dwSts = GetRC4KeyForSymWrap(rgbSymmetricKeyWrapIV, pWrapKey, &pLocalWrapKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
fAlloc = TRUE; }
dwSts = SymEncrypt(pLocalWrapKey, FALSE, rgbTmp1, &cbIndex, cbIndex); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// set the header info
pBlobHdr = (BLOBHEADER*)pbBlob; pBlobHdr->aiKeyAlg = pKey->Algid;
pAlgid = (ALG_ID*)(pbBlob + sizeof(BLOBHEADER)); *pAlgid = pWrapKey->Algid;
memcpy(pbBlob + sizeof(BLOBHEADER) + sizeof(ALG_ID), rgbTmp1, cbIndex);
*pcbBlob = cbIndex + sizeof(BLOBHEADER) + sizeof(ALG_ID); dwReturn = ERROR_SUCCESS;
ErrorExit: if (fAlloc && pLocalWrapKey) FreeNewKey(pLocalWrapKey); memset(rgbTmp1, 0, sizeof(rgbTmp1)); memset(rgbTmp2, 0, sizeof(rgbTmp2)); memset(rgbIV, 0, sizeof(rgbIV)); return dwReturn; }
/*
- UnWrapSymKey - * Purpose: * Unwrap a symmetric key with another symmetric key. This should * meet the CMS specification for symmetric key wrapping. * * Parameters: * IN pTmpUser - Pointer to the user context * IN pWrapKey - Pointer to the key to be used for unwrapping * IN pbBlob - Pointer to the blob to be unwrapped * IN cbBlob - The length of the blob buffer * OUT phKey - Handle to the unwrapped key */
/*static*/ DWORD UnWrapSymKey( IN HCRYPTPROV hUID, IN PNTAGUserList pTmpUser, IN PNTAGKeyList pWrapKey, IN BYTE *pbBlob, IN DWORD cbBlob, IN DWORD dwFlags, OUT HCRYPTKEY *phKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD cb = 0; DWORD cbIndex = 0; DWORD cbKey = 0; BYTE rgbChecksum[8]; BLOBHEADER *pBlobHdr = (BLOBHEADER*)pbBlob; ALG_ID *pAlgid; BYTE rgbTmp1[49]; // 1 length + 8 padding + 8 checksum + 8 IV + 24 max key
BYTE rgbTmp2[49]; // 1 length + 8 padding + 8 checksum + 8 IV + 24 max key
DWORD dwRights = 0; PNTAGKeyList pTmpKey = NULL; PNTAGKeyList pLocalWrapKey = NULL; BOOL fAlloc = FALSE; DWORD i; BOOL fPubKey; DWORD dwSts;
memset(rgbTmp1, 0, sizeof(rgbTmp1)); memset(rgbTmp2, 0, sizeof(rgbTmp2));
cb = cbBlob - (sizeof(BLOBHEADER) + sizeof(ALG_ID)); if ((sizeof(rgbTmp1) < cb) || (0 != (cb % 8))) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// both keys must be supported symmetric keys
if (UnsupportedSymKey(pWrapKey) || UnsupportedSymKey(pWrapKey)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
#ifdef CSP_USE_AES
// For now, punt on supporting AES algs in this scenario
if (CALG_AES_128 == pWrapKey->Algid || CALG_AES_192 == pWrapKey->Algid || CALG_AES_256 == pWrapKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } #endif
if (!FIsLegalKey(pTmpUser, pWrapKey, FALSE)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// check the wrapping key ALG_ID
pAlgid = (ALG_ID*)(pbBlob + sizeof(BLOBHEADER)); if (pWrapKey->Algid != *pAlgid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// Check if we should do an auto-inflate
if (pWrapKey->pData == NULL) { dwSts = InflateKey(pWrapKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
// set the hardcoded IV
if (CALG_RC4 != pWrapKey->Algid) { memcpy(pWrapKey->IV, rgbSymmetricKeyWrapIV, 8); pWrapKey->InProgress = FALSE; pLocalWrapKey = pWrapKey; } else { // RC4 (or more precisely, stream ciphers) are not supported by the
// CMS spec for symmetric key wrapping. Therefore we had to do
// something proprietary to support RC4 for applications other
// than SMIME.
dwSts = GetRC4KeyForSymWrap(rgbSymmetricKeyWrapIV, pWrapKey, &pLocalWrapKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
fAlloc = TRUE; }
memcpy(rgbTmp1, pbBlob + sizeof(BLOBHEADER) + sizeof(ALG_ID), cb);
// decrypt the key blob data
dwSts = SymDecrypt(pLocalWrapKey, 0, FALSE, rgbTmp1, &cb); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// byte reverse the plaintext + IV buffer
for (i = 0; i < cb; i++) rgbTmp2[i] = rgbTmp1[cb - (i + 1)];
// set the IV if the algorithm is not RC4
cb -= 8; if (CALG_RC4 != pWrapKey->Algid) { memcpy(pWrapKey->IV, rgbTmp2, 8); pWrapKey->InProgress = FALSE; } else { if (fAlloc && pLocalWrapKey) { FreeNewKey(pLocalWrapKey); pLocalWrapKey = NULL; fAlloc = FALSE; }
// RC4 (or more precisely, stream ciphers) are not supported by the
// CMS spec for symmetric key wrapping. Therefore we had to do
// something proprietary to support RC4 for applications other
// than SMIME.
dwSts = GetRC4KeyForSymWrap(rgbTmp2, pWrapKey, &pLocalWrapKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
fAlloc = TRUE; }
// decrypt the key blob data again
dwSts = SymDecrypt(pLocalWrapKey, 0, FALSE, rgbTmp2 + 8, &cb); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// check the length of the key
switch (pBlobHdr->aiKeyAlg) { case CALG_RC2: // variable key lengths
case CALG_RC4: cbKey = (DWORD)rgbTmp2[8]; cbIndex += 1; break;
case CALG_DES: // Ignore the default length, and use the full DES length.
case CALG_DESX: case CALG_CYLINK_MEK: cbKey = DES_KEYSIZE; break; case CALG_3DES_112: cbKey = DES_KEYSIZE * 2; break; case CALG_3DES: cbKey = DES_KEYSIZE * 3; break;
default: if (!GetDefaultKeyLength(pTmpUser, pBlobHdr->aiKeyAlg, &cbKey, &fPubKey)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } }
// get the checksum and make sure it matches
cb -= 8; GetSymmetricKeyChecksum(rgbTmp2 + 8, cb, rgbChecksum); if (0 != memcmp(rgbChecksum, rgbTmp2 + 8 + cb, sizeof(rgbChecksum))) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// check if the key is to be exportable
if (dwFlags & CRYPT_EXPORTABLE) dwRights = CRYPT_EXPORTABLE;
dwSts = MakeNewKey(pBlobHdr->aiKeyAlg, dwRights, cbKey, hUID, rgbTmp2 + cbIndex + 8, FALSE, TRUE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// check keylength...
if (!FIsLegalKey(pTmpUser, pTmpKey, TRUE)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// if 40 bit key + no mention of salt, set zeroized salt for
// RSABase compatibility
if ((5 == pTmpKey->cbKeyLen) && (0 == (dwFlags & CRYPT_NO_SALT))) { dwSts = MakeKeyRSABaseCompatible(hUID, *phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
pTmpKey = NULL; dwReturn = ERROR_SUCCESS;
ErrorExit: if (fAlloc && pLocalWrapKey) FreeNewKey(pLocalWrapKey); memset(rgbTmp1, 0, sizeof(rgbTmp1)); memset(rgbTmp2, 0, sizeof(rgbTmp2)); if (NULL != pTmpKey) FreeNewKey(pTmpKey); return dwReturn; }
/*
- CPExportKey - * Purpose: * Export cryptographic keys out of a CSP in a secure manner * * * Parameters: * IN hUID - Handle to the CSP user * IN hKey - Handle to the key to export * IN hPubKey - Handle to the exchange public key value of * the destination user * IN dwBlobType - Type of key blob to be exported * IN dwFlags - Flags values * OUT pbData - Key blob data * OUT pdwDataLen - Length of key blob in bytes * * Returns: */
BOOL WINAPI CPExportKey( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN HCRYPTKEY hPubKey, IN DWORD dwBlobType, IN DWORD dwFlags, OUT BYTE *pbData, OUT DWORD *pdwDataLen) { // return codes
DWORD dwReturn = ERROR_INTERNAL_ERROR; BOOL fRet;
// miscellaneous variables
DWORD dwLen; NTSimpleBlob *pSimpleHeader; BLOBHEADER *pPreHeader; BLOBHEADER shScratch; RSAPUBKEY *pExpPubKey; BSAFE_PUB_KEY *pBsafePubKey; BSAFE_PUB_KEY *pPublicKey; DWORD PubKeyLen; BSAFE_PRV_KEY *pPrvKey = NULL; DWORD PrvKeyLen = 0; DWORD cbPrivateBlob = 0; PBYTE pbPrivateBlob = NULL; DWORD cb = 0; BOOL fExportable = FALSE; DWORD dwSts;
// temporary variables for pointing to user and key records
PNTAGKeyList pTmpKey; PNTAGKeyList pPubKey; PNTAGUserList pTmpUser;
EntryPoint if (0 != (dwFlags & ~(CRYPT_SSL2_FALLBACK | CRYPT_DESTROYKEY | CRYPT_OAEP))) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pdwDataLen == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
if (((PUBLICKEYBLOB == dwBlobType) || (OPAQUEKEYBLOB == dwBlobType) || (PLAINTEXTKEYBLOB == dwBlobType)) && (0 != hPubKey)) { dwReturn = (DWORD)NTE_BAD_PUBLIC_KEY; goto ErrorExit; }
// check the user identification
pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
// check if the user is just looking for a length. If so,
// use a scratchpad to construct a pseudoblob.
if ((pbData != NULL) && (*pdwDataLen > sizeof(BLOBHEADER))) pPreHeader = (BLOBHEADER *)pbData; else pPreHeader = &shScratch;
pPreHeader->bType = (BYTE)(dwBlobType & 0xff); pPreHeader->bVersion = CUR_BLOB_VERSION; pPreHeader->reserved = 0;
dwSts = NTLValidate((HNTAG)hKey, hUID, HNTAG_TO_HTYPE(hKey), &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if ((dwBlobType != PUBLICKEYBLOB) && (0 == (pTmpKey->Rights & (CRYPT_EXPORTABLE | CRYPT_ARCHIVABLE)))) { dwReturn = (DWORD)NTE_BAD_KEY_STATE; goto ErrorExit; }
pPreHeader->aiKeyAlg = pTmpKey->Algid;
switch (dwBlobType) { case PUBLICKEYBLOB: { if ((HNTAG_TO_HTYPE(hKey) != SIGPUBKEY_HANDLE) && (HNTAG_TO_HTYPE(hKey) != EXCHPUBKEY_HANDLE)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue;
if (pBsafePubKey == NULL) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
//
// Subtract off 2 extra DWORD needed by RSA code
//
dwLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + ((pBsafePubKey->bitlen + 7) / 8);
// Check user buffer size
if (pbData == NULL || *pdwDataLen < dwLen) { *pdwDataLen = dwLen; if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
pExpPubKey = (RSAPUBKEY *) (pbData + sizeof(BLOBHEADER)); pExpPubKey->magic = pBsafePubKey->magic; pExpPubKey->bitlen = pBsafePubKey->bitlen; pExpPubKey->pubexp = pBsafePubKey->pubexp;
memcpy((BYTE *) pbData + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), (BYTE *) pBsafePubKey + sizeof(BSAFE_PUB_KEY), ((pBsafePubKey->bitlen + 7) / 8)); break; }
case PRIVATEKEYBLOB: { DWORD dwBlockLen = 0; BOOL fSigKey; LPWSTR szPrompt;
cb = sizeof(DWORD); if (HNTAG_TO_HTYPE(hKey) == SIGPUBKEY_HANDLE) { fSigKey = TRUE; szPrompt = g_Strings.pwszExportPrivSig; pPublicKey = (BSAFE_PUB_KEY*)pTmpUser->ContInfo.pbSigPub; PubKeyLen = pTmpUser->ContInfo.ContLens.cbSigPub; } else if (HNTAG_TO_HTYPE(hKey) == EXCHPUBKEY_HANDLE) { fSigKey = FALSE; szPrompt = g_Strings.pwszExportPrivExch; pPublicKey = (BSAFE_PUB_KEY*)pTmpUser->ContInfo.pbExchPub; PubKeyLen = pTmpUser->ContInfo.ContLens.cbExchPub; } else { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// make sure the public key is available and appropriate
if ((pPublicKey == NULL) || (PubKeyLen != pTmpKey->cbKeyLen) || (0 != memcmp((PBYTE)pPublicKey, pTmpKey->pKeyValue, PubKeyLen))) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
GetLengthOfPrivateKeyForExport(pPublicKey, &cbPrivateBlob);
if (hPubKey) { if (!CPGetKeyParam(hUID, hPubKey, KP_BLOCKLEN, (PBYTE)&dwBlockLen, &cb, 0)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// convert to byte count
dwBlockLen /= 8; }
// Check user buffer size
if (pbData == NULL) { *pdwDataLen = sizeof(BLOBHEADER) + cbPrivateBlob + dwBlockLen; dwReturn = ERROR_SUCCESS; goto ErrorExit; } else if (*pdwDataLen < (sizeof(BLOBHEADER) + cbPrivateBlob + dwBlockLen)) { *pdwDataLen = sizeof(BLOBHEADER) + cbPrivateBlob + dwBlockLen; dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
// if the context being used is a Verify context then the key is not
// in persisted storage and therefore is in memory
if (0 == (pTmpUser->Rights & CRYPT_VERIFYCONTEXT)) { // always read the private key from storage when exporting
dwSts= UnprotectPrivKey(pTmpUser, szPrompt, fSigKey, TRUE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_BAD_KEYSET
goto ErrorExit; } }
if (fSigKey) { PrvKeyLen = pTmpUser->SigPrivLen; pPrvKey = (BSAFE_PRV_KEY*)pTmpUser->pSigPrivKey; fExportable = pTmpUser->ContInfo.fSigExportable; } else { PrvKeyLen = pTmpUser->ExchPrivLen; pPrvKey = (BSAFE_PRV_KEY*)pTmpUser->pExchPrivKey; fExportable = pTmpUser->ContInfo.fExchExportable; }
if (pPrvKey == NULL) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
if (!fExportable && (0 == (CRYPT_ARCHIVABLE & pTmpKey->Rights))) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (!PreparePrivateKeyForExport(pPrvKey, NULL, &cbPrivateBlob)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
// allocate memory for the private key blob
cb = cbPrivateBlob + dwBlockLen; pbPrivateBlob = _nt_malloc(cb); if (NULL == pbPrivateBlob) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
if (!PreparePrivateKeyForExport(pPrvKey, pbPrivateBlob, &cbPrivateBlob)) { // ?BUGBUG? Fix this
dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (hPubKey) { dwSts = LocalEncrypt(hUID, hPubKey, 0, TRUE, 0, pbPrivateBlob, &cbPrivateBlob, cb, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
dwLen = sizeof(BLOBHEADER) + cbPrivateBlob; CopyMemory(pbData + sizeof(BLOBHEADER), pbPrivateBlob, cbPrivateBlob); break; }
case SIMPLEBLOB: { if (HNTAG_TO_HTYPE(hKey) != KEY_HANDLE) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (0 == hPubKey) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
if (!FIsLegalKey(pTmpUser, pTmpKey, FALSE)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
#ifdef CSP_USE_SSL3
// if the SSL2_FALLBACK flag is set then make sure the key
// is an SSL2 master key
if (CRYPT_SSL2_FALLBACK & dwFlags) { if (CALG_SSL2_MASTER != pTmpKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } } #endif
dwSts = NTLValidate((HNTAG)hPubKey, hUID, EXCHPUBKEY_HANDLE, &pPubKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
pBsafePubKey = (BSAFE_PUB_KEY *) pPubKey->pKeyValue; if (pBsafePubKey == NULL) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
//
// Subtract off 8 bytes for 2 extra DWORD needed by RSA code
dwLen = sizeof(BLOBHEADER) + sizeof(NTSimpleBlob) + (pBsafePubKey->bitlen + 7) / 8;
if (pbData == NULL || *pdwDataLen < dwLen) { *pdwDataLen = dwLen; // set what we need
if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
pSimpleHeader = (NTSimpleBlob *) (pbData + sizeof(BLOBHEADER)); pSimpleHeader->aiEncAlg = CALG_RSA_KEYX;
#ifdef USE_SGC
// if this is the schannel provider and we are a verify context and
// the SGC flags are set and the key is large then make sure the
// key is the same as the SGC key
if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && (0 != pTmpUser->dwSGCFlags) && (pTmpUser->Rights & CRYPT_VERIFYCONTEXT) && (pBsafePubKey->bitlen > 1024)) { if (!CheckSGCSimpleForExport(pTmpUser, pBsafePubKey)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } } #endif
// perform the RSA encryption.
dwSts = RSAEncrypt(pTmpUser, pBsafePubKey, pTmpKey->pKeyValue, pTmpKey->cbKeyLen, pTmpKey->pbParams, pTmpKey->cbParams, dwFlags, pbData + sizeof(BLOBHEADER) + sizeof(NTSimpleBlob)); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; }
case OPAQUEKEYBLOB: { dwLen = *pdwDataLen; dwSts = ExportOpaqueBlob(pTmpKey, pbData, &dwLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// if the destroy key flag is set then destroy the key
if (CRYPT_DESTROYKEY & dwFlags) { if (!CPDestroyKey(hUID, hKey)) { dwReturn = GetLastError(); goto ErrorExit; } }
break; }
case SYMMETRICWRAPKEYBLOB: { // get a pointer to the symmetric key to wrap with (the variable
// name pPubKey is a misnomer)
dwSts = NTLValidate((HNTAG)hPubKey, hUID, HNTAG_TO_HTYPE(hKey), &pPubKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
dwSts = WrapSymKey(pTmpUser, pTmpKey, pPubKey, pbData, pdwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwLen = *pdwDataLen; break; }
case PLAINTEXTKEYBLOB: { if (HNTAG_TO_HTYPE(hKey) != KEY_HANDLE) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (! FIsLegalKey(pTmpUser, pTmpKey, FALSE)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
dwLen = sizeof(BLOBHEADER) + sizeof(DWORD) + pTmpKey->cbKeyLen; if (NULL == pbData || *pdwDataLen < dwLen) { *pdwDataLen = dwLen; if (NULL == pbData) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
pbData += sizeof(BLOBHEADER); *((DWORD*)pbData) = pTmpKey->cbKeyLen; pbData += sizeof(DWORD); memcpy(pbData, pTmpKey->pKeyValue, pTmpKey->cbKeyLen); *pdwDataLen = dwLen; break; }
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
// set the size of the key blob
*pdwDataLen = dwLen; dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (pbPrivateBlob) _nt_free(pbPrivateBlob, cb); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ DWORD ImportOpaqueBlob( HCRYPTPROV hUID, CONST BYTE *pbData, DWORD cbData, HCRYPTKEY *phKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGKeyList pTmpKey = NULL; PNTAGPackedKeyList pPackedKey; DWORD cbRequired; DWORD dwSts;
*phKey = 0;
// allocate a temporary key structure
pTmpKey = (PNTAGKeyList)_nt_malloc(sizeof(NTAGKeyList)); if (NULL == pTmpKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
// make sure we have enough data
cbRequired = sizeof(BLOBHEADER) + sizeof(NTAGPackedKeyList);
if (cbData < cbRequired) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// build key structure from packed key structure
pPackedKey = (PNTAGPackedKeyList)(pbData + sizeof(BLOBHEADER));
pTmpKey->hUID = hUID; pTmpKey->Algid = pPackedKey->Algid; pTmpKey->Rights = pPackedKey->Rights; pTmpKey->cbKeyLen = pPackedKey->cbKeyLen; pTmpKey->cbDataLen = pPackedKey->cbDataLen; memcpy(pTmpKey->IV, pPackedKey->IV, sizeof(pTmpKey->IV)); memcpy(pTmpKey->FeedBack, pPackedKey->FeedBack, sizeof(pTmpKey->FeedBack)); pTmpKey->InProgress = pPackedKey->InProgress; pTmpKey->cbSaltLen = pPackedKey->cbSaltLen; memcpy(pTmpKey->rgbSalt, pPackedKey->rgbSalt, sizeof(pTmpKey->rgbSalt)); pTmpKey->Padding = pPackedKey->Padding; pTmpKey->Mode = pPackedKey->Mode; pTmpKey->ModeBits = pPackedKey->ModeBits; pTmpKey->Permissions = pPackedKey->Permissions; pTmpKey->EffectiveKeyLen = pPackedKey->EffectiveKeyLen; pTmpKey->dwBlockLen = pPackedKey->dwBlockLen;
// make sure we still have enough data
cbRequired += pTmpKey->cbKeyLen + pTmpKey->cbDataLen;
if (cbData < cbRequired) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// allocate memory and copy the key value
if (0 < pTmpKey->cbKeyLen) { pTmpKey->pKeyValue = _nt_malloc(pTmpKey->cbKeyLen); if (NULL == pTmpKey->pKeyValue) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pTmpKey->pKeyValue, (PBYTE)pPackedKey + sizeof(NTAGPackedKeyList), pTmpKey->cbKeyLen); }
// allocate memory and copy the key data
if (0 < pTmpKey->cbDataLen) { pTmpKey->pData = _nt_malloc(pTmpKey->cbDataLen); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pTmpKey->pData, (PBYTE)pPackedKey + sizeof(NTAGPackedKeyList) + pTmpKey->cbKeyLen, pTmpKey->cbDataLen); }
dwSts = NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
pTmpKey = NULL; dwReturn = ERROR_SUCCESS;
ErrorExit: if (NULL != pTmpKey) FreeNewKey(pTmpKey); return dwReturn; }
/*
- CPImportKey - * Purpose: * Import cryptographic keys * * * Parameters: * IN hUID - Handle to the CSP user * IN pbData - Key blob data * IN dwDataLen - Length of the key blob data * IN hPubKey - Handle to the exchange public key value of * the destination user * IN dwFlags - Flags values * OUT phKey - Pointer to the handle to the key which was * Imported * * Returns: */
BOOL WINAPI CPImportKey( IN HCRYPTPROV hUID, IN CONST BYTE *pbData, IN DWORD dwDataLen, IN HCRYPTKEY hPubKey, IN DWORD dwFlags, OUT HCRYPTKEY *phKey) { // Status return variables
DWORD dwReturn = ERROR_INTERNAL_ERROR; BOOL fRet;
// miscellaneous variables
DWORD KeyBufLen; CONST BYTE *pbEncPortion; BLOBHEADER *ThisStdHeader = (BLOBHEADER *)pbData; BSAFE_PRV_KEY *pBsafePrvKey = NULL; BYTE *pKeyBuf = NULL; DWORD dwRights = 0; DWORD cbTmpLen; DWORD dwSts;
// temporary variables for pointing to user and key records
PNTAGUserList pTmpUser = NULL; PNTAGKeyList pTmpKey = NULL; LPWSTR szPrompt; BLOBHEADER *pPublic; RSAPUBKEY *pImpPubKey; BSAFE_PUB_KEY *pBsafePubKey; PBYTE pbData2 = NULL; DWORD cb; DWORD *pcbPub; BYTE **ppbPub; DWORD *pcbPrv; BYTE **ppbPrv; BOOL *pfExportable; BOOL fExch; PEXPORT_PRV_KEY pExportKey; BOOL fPubKey = FALSE; NTSimpleBlob *ThisSB; PNTAGKeyList pExPubKey = NULL; BOOL fInCritSec = FALSE; BYTE *pbParams = NULL; DWORD cbParams = 0; BOOL fAllowBigRC2Key = FALSE;
EntryPoint // Validate user pointer
// count = *phKey;
if ((dwFlags & ~(CRYPT_USER_PROTECTED | CRYPT_EXPORTABLE | CRYPT_NO_SALT | CRYPT_SGCKEY | CRYPT_OAEP | CRYPT_IPSEC_HMAC_KEY)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if ((PUBLICKEYBLOB == ThisStdHeader->bType) && (0 != hPubKey)) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
// check the user identification
pTmpUser = (PNTAGUserList)NTLCheckList((HNTAG)hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if (ThisStdHeader->bVersion != CUR_BLOB_VERSION) { dwReturn = (DWORD)NTE_BAD_VER; goto ErrorExit; }
// Handy pointer for decrypting the blob...
pbEncPortion = pbData + sizeof(BLOBHEADER) + sizeof(NTSimpleBlob);
// determine which key blob is being imported
switch (ThisStdHeader->bType) { case PUBLICKEYBLOB: pPublic = (BLOBHEADER *) pbData; pImpPubKey = (RSAPUBKEY *)(pbData+sizeof(BLOBHEADER));
if ((pPublic->aiKeyAlg != CALG_RSA_KEYX) && (pPublic->aiKeyAlg != CALG_RSA_SIGN)) { dwReturn =(DWORD)NTE_BAD_DATA; goto ErrorExit; }
cbTmpLen = (sizeof(DWORD) * 2) - (((pImpPubKey->bitlen + 7) / 8) % (sizeof(DWORD) * 2)); if ((sizeof(DWORD) * 2) != cbTmpLen) cbTmpLen += sizeof(DWORD) * 2; dwSts = MakeNewKey(pPublic->aiKeyAlg, 0, sizeof(BSAFE_PUB_KEY) + (pImpPubKey->bitlen / 8) + cbTmpLen, hUID, 0, FALSE, TRUE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
pBsafePubKey = (BSAFE_PUB_KEY *)pTmpKey->pKeyValue; pBsafePubKey->magic = pImpPubKey->magic; pBsafePubKey->keylen = (pImpPubKey->bitlen / 8) + cbTmpLen; pBsafePubKey->bitlen = pImpPubKey->bitlen; pBsafePubKey->datalen = (pImpPubKey->bitlen+7)/8 - 1; pBsafePubKey->pubexp = pImpPubKey->pubexp;
memset((BYTE *) pBsafePubKey + sizeof(BSAFE_PUB_KEY), '\0', pBsafePubKey->keylen);
memcpy((BYTE *) pBsafePubKey + sizeof(BSAFE_PUB_KEY), (BYTE *) pPublic + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), (pImpPubKey->bitlen+7)/8);
dwSts = NTLMakeItem(phKey, (BYTE) (pPublic->aiKeyAlg == CALG_RSA_KEYX ? EXCHPUBKEY_HANDLE : SIGPUBKEY_HANDLE), (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case PRIVATEKEYBLOB: // wrap with a try since there is a critical section in here
__try { EnterCriticalSection(&pTmpUser->CritSec); fInCritSec = TRUE;
pPublic = (BLOBHEADER *) pbData; cb = dwDataLen - sizeof(BLOBHEADER); pbData2 = _nt_malloc(cb); if (NULL == pbData2) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
CopyMemory(pbData2, pbData + sizeof(BLOBHEADER), cb); if (hPubKey) { dwSts = LocalDecrypt(hUID, hPubKey, 0, TRUE, 0, pbData2, &cb, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
if (pPublic->aiKeyAlg == CALG_RSA_KEYX) { if (PROV_RSA_SIG == pTmpUser->dwProvType) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } pcbPub = &pTmpUser->ContInfo.ContLens.cbExchPub; ppbPub = &pTmpUser->ContInfo.pbExchPub; pcbPrv = &pTmpUser->ExchPrivLen; ppbPrv = &pTmpUser->pExchPrivKey; pfExportable = &pTmpUser->ContInfo.fExchExportable; fExch = TRUE; szPrompt = g_Strings.pwszImportPrivExch; } else if (pPublic->aiKeyAlg == CALG_RSA_SIGN) { if (PROV_RSA_SCHANNEL == pTmpUser->dwProvType) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } pcbPub = &pTmpUser->ContInfo.ContLens.cbSigPub; ppbPub = &pTmpUser->ContInfo.pbSigPub; pcbPrv = &pTmpUser->SigPrivLen; ppbPrv = &pTmpUser->pSigPrivKey; fExch = FALSE; pfExportable = &pTmpUser->ContInfo.fSigExportable; szPrompt = g_Strings.pwszImportPrivSig; } else { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// check the length of the key exchange key
pExportKey = (PEXPORT_PRV_KEY)pbData2;
#ifdef USE_SGC
// check if the provider is an SChannel provider and if so if the
// SGC flag is set then use the FIsLegalSGCKeySize function
if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && (!(pTmpUser->Rights & CRYPT_VERIFYCONTEXT)) && (0 != pTmpUser->dwSGCFlags)) // make sure this is server side
{ if (!FIsLegalSGCKeySize(pPublic->aiKeyAlg, pExportKey->bitlen / 8, FALSE, FALSE, &fPubKey)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } } else #endif
{ if (!FIsLegalKeySize(pTmpUser->dwCspTypeId, pPublic->aiKeyAlg, pExportKey->bitlen / 8, FALSE, &fPubKey)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } }
if (!fPubKey) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
if (*ppbPub) { ASSERT(*pcbPub); ASSERT(*pcbPrv); ASSERT(*ppbPrv);
_nt_free(*ppbPub, *pcbPub); *ppbPub = NULL; *pcbPub = 0;
_nt_free(*ppbPrv, *pcbPrv); *ppbPrv = NULL; *pcbPrv = 0; }
if (!PreparePrivateKeyForImport(pbData2, NULL, pcbPrv, NULL, pcbPub)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
*ppbPub = _nt_malloc(*pcbPub); if (NULL == *ppbPub) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
*ppbPrv = _nt_malloc(*pcbPrv); if (NULL == *ppbPrv) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
if (!PreparePrivateKeyForImport(pbData2, (LPBSAFE_PRV_KEY)*ppbPrv, pcbPrv, (LPBSAFE_PUB_KEY)*ppbPub, pcbPub)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
if (dwFlags & CRYPT_EXPORTABLE) *pfExportable = TRUE; else *pfExportable = FALSE;
// test the RSA key to make sure it works
dwSts = EncryptAndDecryptWithRSAKey(*ppbPub, *ppbPrv, TRUE, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_BAD_DATA
goto ErrorExit; }
dwSts = EncryptAndDecryptWithRSAKey(*ppbPub, *ppbPrv, FALSE, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_BAD_DATA
goto ErrorExit; }
// if the context being used is a Verify Context then the key
// is not persisted to storage
if (0 == (pTmpUser->Rights & CRYPT_VERIFYCONTEXT)) { // write the new keys to the user storage file
dwSts = ProtectPrivKey(pTmpUser, szPrompt, dwFlags, (!fExch)); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
if (!CPGetUserKey(hUID, (fExch ? AT_KEYEXCHANGE : AT_SIGNATURE), phKey)) { dwReturn = GetLastError(); goto ErrorExit; } } __except ( EXCEPTION_EXECUTE_HANDLER ) { // ?BUGBUG? No it's not!
dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; } break;
case SIMPLEBLOB: ThisSB = (NTSimpleBlob *) (pbData + sizeof(BLOBHEADER));
if (!ValidKeyAlgid(pTmpUser, ThisStdHeader->aiKeyAlg)) { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
if (ThisSB->aiEncAlg != CALG_RSA_KEYX) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
// if the import key handle is not zero make sure it is the
if (0 != hPubKey) { dwSts = NTLValidate((HNTAG)hPubKey, hUID, HNTAG_TO_HTYPE((HNTAG)hPubKey), &pExPubKey); 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_KEY : dwSts; goto ErrorExit; }
if ((pTmpUser->ContInfo.ContLens.cbExchPub != pExPubKey->cbKeyLen) || (0 != memcmp((PBYTE)pExPubKey->pKeyValue, pTmpUser->ContInfo.pbExchPub, pExPubKey->cbKeyLen))) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
pbParams = pExPubKey->pbParams; cbParams = pExPubKey->cbParams; }
pBsafePubKey = (BSAFE_PUB_KEY *)pTmpUser->ContInfo.pbExchPub; if (NULL == pBsafePubKey) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
#ifdef USE_SGC
// check if the provider is an SChannel provider and if so if the
// SGC flag is set then use the FIsLegalSGCKeySize function
if ((PROV_RSA_SCHANNEL == pTmpUser->dwProvType) && (!(pTmpUser->Rights & CRYPT_VERIFYCONTEXT)) && (0 != pTmpUser->dwSGCFlags)) // make sure this is server side
{ if (!FIsLegalSGCKeySize(CALG_RSA_KEYX, pBsafePubKey->bitlen / 8, FALSE, FALSE, &fPubKey)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } } else #endif
{ if (!FIsLegalKeySize(pTmpUser->dwCspTypeId, CALG_RSA_KEYX, pBsafePubKey->bitlen / 8, FALSE, &fPubKey)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } }
// get the key to use
dwSts = UnprotectPrivKey(pTmpUser, g_Strings.pwszImportSimple, FALSE, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_NO_KEY
goto ErrorExit; }
pBsafePrvKey = (BSAFE_PRV_KEY *)pTmpUser->pExchPrivKey; if (NULL == pBsafePrvKey) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
// Check the input data length
if ((dwDataLen - (sizeof(BLOBHEADER) + sizeof(NTSimpleBlob))) < ((pBsafePrvKey->bitlen + 7) / 8)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// perform the RSA decryption
dwSts = RSADecrypt(pTmpUser, pBsafePrvKey, pbData + sizeof(BLOBHEADER) + sizeof(NTSimpleBlob), dwDataLen - (sizeof(BLOBHEADER) + sizeof(NTSimpleBlob)), pbParams, cbParams, dwFlags, &pKeyBuf, &KeyBufLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// check if the key is CRYPT_EXPORTABLE
if (dwFlags & CRYPT_EXPORTABLE) dwRights = CRYPT_EXPORTABLE;
#ifdef CSP_USE_SSL3
// if SSL3 or TLS1 master key then check the version
if (CALG_SSL3_MASTER == ThisStdHeader->aiKeyAlg || CALG_TLS1_MASTER == ThisStdHeader->aiKeyAlg) { if (MAKEWORD(pKeyBuf[1], pKeyBuf[0]) < 0x300) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } } #endif // CSP_USE_SSL3
dwSts = MakeNewKey(ThisStdHeader->aiKeyAlg, dwRights, KeyBufLen, hUID, pKeyBuf, TRUE, TRUE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
pKeyBuf = NULL;
// check keylength...
if (!FIsLegalImportSymKey(pTmpUser, pTmpKey, TRUE)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// if 40 bit key + no mention of salt, set zeroized salt for
// RSABase compatibility
if ((5 == KeyBufLen) && (0 == (dwFlags & CRYPT_NO_SALT)) && (CALG_SSL2_MASTER != ThisStdHeader->aiKeyAlg)) { dwSts = MakeKeyRSABaseCompatible(hUID, *phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } break;
case OPAQUEKEYBLOB: dwSts = ImportOpaqueBlob(hUID, pbData, dwDataLen, phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case SYMMETRICWRAPKEYBLOB: // get a pointer to the symmetric key to unwrap with (the variable
// name pExPubKey is a misnomer)
dwSts = NTLValidate((HNTAG)hPubKey, hUID, HNTAG_TO_HTYPE((HNTAG)hPubKey), &pExPubKey); 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_KEY : dwSts; goto ErrorExit; }
dwSts = UnWrapSymKey(hUID, pTmpUser, pExPubKey, (BYTE*)pbData, dwDataLen, dwFlags, phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
break;
case PLAINTEXTKEYBLOB: if (! ValidKeyAlgid(pTmpUser, ThisStdHeader->aiKeyAlg)) { dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
// check if the key is CRYPT_EXPORTABLE
if (dwFlags & CRYPT_EXPORTABLE) dwRights = CRYPT_EXPORTABLE;
KeyBufLen = *((DWORD*)(pbData + sizeof(BLOBHEADER))); dwSts = MakeNewKey( ThisStdHeader->aiKeyAlg, dwRights, KeyBufLen, hUID, (BYTE *) (pbData + sizeof(BLOBHEADER) + sizeof(DWORD)), FALSE, TRUE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
if (CRYPT_IPSEC_HMAC_KEY & dwFlags) fAllowBigRC2Key = TRUE;
if (! FIsLegalImportSymKey(pTmpUser, pTmpKey, fAllowBigRC2Key)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } dwSts = NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } // if 40 bit key + no mention of salt, set zeroized salt for
// RSABase compatibility
if ((5 == KeyBufLen) && (0 == (dwFlags & CRYPT_NO_SALT)) && (CALG_SSL2_MASTER != ThisStdHeader->aiKeyAlg)) { dwSts = MakeKeyRSABaseCompatible(hUID, *phKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } break;
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
pTmpKey = NULL; dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (fInCritSec) LeaveCriticalSection(&pTmpUser->CritSec); if (pKeyBuf) _nt_free(pKeyBuf, KeyBufLen); if (pbData2) _nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER)); if (NULL != pTmpKey) FreeNewKey(pTmpKey); if (!fRet) SetLastError(dwReturn); return fRet; }
/*
- CPInflateKey - * Purpose: * Use to "inflate" (expand) a cryptographic key for use with * the CryptEncrypt and CryptDecrypt functions * * Parameters: * IN hUID - Handle to a CSP * IN hKey - Handle to a key * IN dwFlags - Flags values * * Returns: */
DWORD InflateKey( IN PNTAGKeyList pTmpKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; BYTE *pbRealKey = NULL;
// if space for the key table has been allocated previously
// then free it
if (pTmpKey->pData != NULL) { ASSERT(0 != pTmpKey->cbDataLen); _nt_free(pTmpKey->pData, pTmpKey->cbDataLen); pTmpKey->cbDataLen = 0; } else { ASSERT(pTmpKey->cbDataLen == 0); }
// determine the algorithm to be used
switch (pTmpKey->Algid) { #ifdef CSP_USE_RC2
case CALG_RC2: pTmpKey->pData = (BYTE *)_nt_malloc(RC2_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; return NTF_FAILED; }
pbRealKey = (BYTE *)_nt_malloc(pTmpKey->cbKeyLen + pTmpKey->cbSaltLen); if (NULL == pbRealKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pbRealKey, pTmpKey->pKeyValue, pTmpKey->cbKeyLen); memcpy(pbRealKey+pTmpKey->cbKeyLen, pTmpKey->rgbSalt, pTmpKey->cbSaltLen); pTmpKey->cbDataLen = RC2_TABLESIZE;
RC2KeyEx((WORD *)pTmpKey->pData, pbRealKey, pTmpKey->cbKeyLen + pTmpKey->cbSaltLen, pTmpKey->EffectiveKeyLen); break; #endif
#ifdef CSP_USE_RC4
case CALG_RC4: pTmpKey->pData = (BYTE *)_nt_malloc(sizeof(RC4_KEYSTRUCT)); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pbRealKey = (BYTE *)_nt_malloc(pTmpKey->cbKeyLen + pTmpKey->cbSaltLen); if (NULL == pbRealKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pbRealKey, pTmpKey->pKeyValue, pTmpKey->cbKeyLen); memcpy(pbRealKey+pTmpKey->cbKeyLen, pTmpKey->rgbSalt, pTmpKey->cbSaltLen); pTmpKey->cbDataLen = sizeof(RC4_KEYSTRUCT); rc4_key((struct RC4_KEYSTRUCT *)pTmpKey->pData, pTmpKey->cbKeyLen+pTmpKey->cbSaltLen, pbRealKey); break; #endif
#ifdef CSP_USE_DES
case CALG_DES: pTmpKey->pData = (BYTE *)_nt_malloc(DES_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pTmpKey->cbDataLen = DES_TABLESIZE; deskey((DESTable *)pTmpKey->pData, pTmpKey->pKeyValue); break; #endif
#ifdef CSP_USE_3DES
case CALG_3DES_112: pTmpKey->pData = (BYTE *)_nt_malloc(DES3_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pTmpKey->cbDataLen = DES3_TABLESIZE; tripledes2key((PDES3TABLE)pTmpKey->pData, pTmpKey->pKeyValue); break;
case CALG_3DES: pTmpKey->pData = (BYTE *)_nt_malloc(DES3_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pTmpKey->cbDataLen = DES3_TABLESIZE; tripledes3key((PDES3TABLE)pTmpKey->pData, pTmpKey->pKeyValue); break; #endif
#ifdef CSP_USE_SSL3
case CALG_SSL3_MASTER: case CALG_PCT1_MASTER: case CALG_SCHANNEL_MAC_KEY: break; #endif
#ifdef CSP_USE_AES
case CALG_AES_128: pTmpKey->pData = (BYTE *)_nt_malloc(AES_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pTmpKey->cbDataLen = AES_TABLESIZE; aeskey((AESTable *)pTmpKey->pData, pTmpKey->pKeyValue, CRYPT_AES128_ROUNDS); break; case CALG_AES_192: pTmpKey->pData = (BYTE *)_nt_malloc(AES_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pTmpKey->cbDataLen = AES_TABLESIZE; aeskey((AESTable *)pTmpKey->pData, pTmpKey->pKeyValue, CRYPT_AES192_ROUNDS); break; case CALG_AES_256: pTmpKey->pData = (BYTE *)_nt_malloc(AES_TABLESIZE); if (NULL == pTmpKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pTmpKey->cbDataLen = AES_TABLESIZE; aeskey((AESTable *)pTmpKey->pData, pTmpKey->pKeyValue, CRYPT_AES256_ROUNDS); break; #endif
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: if (pbRealKey) _nt_free(pbRealKey, pTmpKey->cbKeyLen + pTmpKey->cbSaltLen); return dwReturn; }
/*
- CPDestroyKey - * Purpose: * Destroys the cryptographic key that is being referenced * with the hKey parameter * * * Parameters: * IN hUID - Handle to a CSP * IN hKey - Handle to a key * * Returns: */
BOOL WINAPI CPDestroyKey( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGKeyList pTmpKey; BOOL fRet; DWORD dwSts;
EntryPoint // check the user identification
if (NULL == NTLCheckList((HNTAG)hUID, USER_HANDLE)) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
dwSts = NTLValidate((HNTAG)hKey, hUID, SIGPUBKEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate((HNTAG)hKey, hUID, EXCHPUBKEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate((HNTAG)hKey, hUID, KEY_HANDLE, &pTmpKey); 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_KEY : dwSts; goto ErrorExit; } } }
// Remove from internal list first so others can't get to it, then free.
NTLDelete((HNTAG)hKey);
// scrub the memory where the key information was held
if (pTmpKey->pKeyValue) { ASSERT(pTmpKey->cbKeyLen); memnuke(pTmpKey->pKeyValue, pTmpKey->cbKeyLen); _nt_free(pTmpKey->pKeyValue, pTmpKey->cbKeyLen); } if (pTmpKey->pbParams) _nt_free(pTmpKey->pbParams, pTmpKey->cbParams); if (pTmpKey->pData) { ASSERT(pTmpKey->cbDataLen); if ((CALG_SSL3_MASTER == pTmpKey->Algid) || (CALG_PCT1_MASTER == pTmpKey->Algid)) { FreeSChKey((PSCH_KEY)pTmpKey->pData); } memnuke(pTmpKey->pData, pTmpKey->cbDataLen); _nt_free(pTmpKey->pData, pTmpKey->cbDataLen); } _nt_free(pTmpKey, sizeof(NTAGKeyList));
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*
- CPGetUserKey - * Purpose: * Gets a handle to a permanent user key * * * Parameters: * IN hUID - Handle to the user identifcation * IN dwWhichKey - Specification of the key to retrieve * OUT phKey - Pointer to key handle of retrieved key * * Returns: */
BOOL WINAPI CPGetUserKey( IN HCRYPTPROV hUID, IN DWORD dwWhichKey, OUT HCRYPTKEY *phKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pUser; PNTAGKeyList pTmpKey; ALG_ID Algid; DWORD cb; BYTE *pb; BYTE bType; DWORD dwExportability = 0; BOOL fRet; DWORD dwSts;
EntryPoint // check the user identification
pUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
switch (dwWhichKey) { case AT_KEYEXCHANGE: Algid = CALG_RSA_KEYX; cb = pUser->ContInfo.ContLens.cbExchPub; pb = pUser->ContInfo.pbExchPub; if (pUser->ContInfo.fExchExportable) dwExportability = CRYPT_EXPORTABLE; bType = EXCHPUBKEY_HANDLE; break;
case AT_SIGNATURE: Algid = CALG_RSA_SIGN; cb = pUser->ContInfo.ContLens.cbSigPub; pb = pUser->ContInfo.pbSigPub; if (pUser->ContInfo.fSigExportable) dwExportability = CRYPT_EXPORTABLE; bType = SIGPUBKEY_HANDLE; break;
default: dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (!ValidKeyAlgid(pUser, Algid)) { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
if (0 == cb) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; }
dwSts = MakeNewKey(Algid, dwExportability, cb, hUID, pb, FALSE, FALSE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwSts = NTLMakeItem(phKey, bType, (void *)pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*
- CPSetKeyParam - * Purpose: * Allows applications to customize various aspects of the * operations of a key * * Parameters: * IN hUID - Handle to a CSP * IN hKey - Handle to a key * IN dwParam - Parameter number * IN pbData - Pointer to data * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPSetKeyParam( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN DWORD dwParam, IN CONST BYTE *pbData, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; PNTAGKeyList pTmpKey; PCRYPT_DATA_BLOB psData; DWORD *pdw; DWORD dw; BOOL fRet; DWORD dwSts;
EntryPoint if ((dwFlags & ~CRYPT_SERVER) != 0) { 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((HNTAG)hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate((HNTAG)hKey, hUID, SIGPUBKEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate((HNTAG)hKey, hUID, EXCHPUBKEY_HANDLE, &pTmpKey); 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_KEY : dwSts; goto ErrorExit; } } }
switch (dwParam) { case KP_IV: memcpy(pTmpKey->IV, pbData, RC2_BLOCKLEN); break;
case KP_SALT: if ((CALG_RC2 != pTmpKey->Algid) && (CALG_RC4 != pTmpKey->Algid)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (pbData == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) || (POLICY_MS_STRONG == pTmpUser->dwCspTypeId)) { pTmpKey->cbSaltLen = DEFAULT_WEAK_SALT_LENGTH; } else { pTmpKey->cbSaltLen = DEFAULT_STRONG_SALT_LENGTH; }
if (pTmpKey->cbSaltLen) CopyMemory(pTmpKey->rgbSalt, pbData, pTmpKey->cbSaltLen);
dwSts = InflateKey(pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case KP_SALT_EX: if ((CALG_RC2 != pTmpKey->Algid) && (CALG_RC4 != pTmpKey->Algid)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
psData = (PCRYPT_DATA_BLOB)pbData; if (pbData == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
if (psData->cbData > MAX_SALT_LEN) { dwReturn = NTE_BAD_DATA; goto ErrorExit; }
pTmpKey->cbSaltLen = psData->cbData; CopyMemory(pTmpKey->rgbSalt, psData->pbData, pTmpKey->cbSaltLen);
dwSts = InflateKey(pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case KP_PADDING: if (*((DWORD *) pbData) != PKCS5_PADDING) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } break;
case KP_MODE: if ((CALG_RSA_SIGN == pTmpKey->Algid) || (CALG_RSA_KEYX == pTmpKey->Algid)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (*pbData != CRYPT_MODE_CBC && *pbData != CRYPT_MODE_ECB && *pbData != CRYPT_MODE_CFB && *pbData != CRYPT_MODE_OFB) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
pTmpKey->Mode = *((DWORD *) pbData); break;
case KP_MODE_BITS: dw = *((DWORD *) pbData); if ((dw == 0) || (dw > 64)) // if 0 or larger than the blocklength
{ dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
pTmpKey->ModeBits = dw; break;
case KP_PERMISSIONS: { DWORD dwPerm = *(LPDWORD)pbData;
if (0 != (dwPerm & ~(CRYPT_ENCRYPT|CRYPT_DECRYPT|CRYPT_EXPORT| CRYPT_READ|CRYPT_WRITE|CRYPT_MAC|CRYPT_ARCHIVE))) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// the exportability of a key may not be changed, but it may be ignored.
if (0 != (dwPerm & CRYPT_EXPORT) && 0 == (pTmpKey->Permissions & CRYPT_EXPORT)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } if (0 != (dwPerm & CRYPT_ARCHIVE) && 0 == (pTmpKey->Permissions & CRYPT_ARCHIVE)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
dwPerm &= ~(CRYPT_ARCHIVE | CRYPT_EXPORT); dwPerm |= pTmpKey->Permissions & (CRYPT_ARCHIVE | CRYPT_EXPORT); pTmpKey->Permissions = dwPerm; break; }
case KP_EFFECTIVE_KEYLEN: if (CALG_RC2 != pTmpKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
pdw = (DWORD*)pbData; if (*pdw < RC2_MIN_EFFECTIVE_KEYLEN) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } if (POLICY_MS_DEF == pTmpUser->dwCspTypeId) { if (*pdw > RC2_MAX_WEAK_EFFECTIVE_KEYLEN) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } } else { if (*pdw > RC2_MAX_STRONG_EFFECTIVE_KEYLEN) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } }
pTmpKey->EffectiveKeyLen = *pdw;
dwSts = InflateKey(pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
#ifdef CSP_USE_SSL3
case KP_CLIENT_RANDOM: case KP_SERVER_RANDOM: case KP_CERTIFICATE: case KP_CLEAR_KEY: case KP_SCHANNEL_ALG: if (PROV_RSA_SCHANNEL != pTmpUser->dwProvType) { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwSts = SCHSetKeyParam(pTmpUser, pTmpKey, dwParam, pbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif // CSP_USE_SSL3
case KP_OAEP_PARAMS: if (CALG_RSA_KEYX != pTmpKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
psData = (PCRYPT_DATA_BLOB)pbData; if (pbData == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
// free salt if it already exists
if (NULL != pTmpKey->pbParams) { _nt_free(pTmpKey->pbParams, pTmpKey->cbParams); pTmpKey->pbParams = NULL; } pTmpKey->cbParams = psData->cbData;
// alloc variable size
pTmpKey->pbParams = (BYTE *)_nt_malloc(pTmpKey->cbParams); if (NULL == pTmpKey->pbParams) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; pTmpKey->cbParams = 0; goto ErrorExit; }
CopyMemory(pTmpKey->pbParams, psData->pbData, pTmpKey->cbParams); break;
#ifdef CSP_USE_SSL3
case KP_HIGHEST_VERSION: if ((CALG_SSL3_MASTER != pTmpKey->Algid) && (CALG_TLS1_MASTER != pTmpKey->Algid)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (pbData == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
if (dwFlags & CRYPT_SERVER) { if ((CALG_SSL3_MASTER == pTmpKey->Algid) && (*(DWORD *)pbData >= 0x301)) { // We're a server doing SSL3, and we also support TLS1.
// If the pre_master_secret contains a version number
// greater than or equal to TLS1, then abort the connection.
if (MAKEWORD(pTmpKey->pKeyValue[1], pTmpKey->pKeyValue[0]) >= 0x301) { dwReturn = (DWORD)NTE_BAD_VER; goto ErrorExit; } } } else { pTmpKey->pKeyValue[0] = HIBYTE(*(DWORD *)pbData); pTmpKey->pKeyValue[1] = LOBYTE(*(DWORD *)pbData); } break; #endif // CSP_USE_SSL3
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*
- CPGetKeyParam - * Purpose: * Allows applications to get various aspects of the * operations of a key * * Parameters: * IN hUID - Handle to a CSP * IN hKey - Handle to a key * IN dwParam - Parameter number * IN pbData - Pointer to data * IN pdwDataLen - Length of parameter data * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPGetKeyParam( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN DWORD dwParam, IN BYTE *pbData, IN DWORD *pwDataLen, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; PNTAGKeyList pTmpKey; BSAFE_PUB_KEY *pBsafePubKey; DWORD *pdw; BOOL fRet; DWORD dwSts;
EntryPoint if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check the user identification
pTmpUser = NTLCheckList((HNTAG)hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
dwSts = NTLValidate((HNTAG)hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate((HNTAG)hKey, hUID, SIGPUBKEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate((HNTAG)hKey, hUID, EXCHPUBKEY_HANDLE, &pTmpKey); 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_KEY : dwSts; goto ErrorExit; } } }
if (pwDataLen == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
switch (dwParam) { case KP_IV: if (pbData == NULL || *pwDataLen < RC2_BLOCKLEN) { *pwDataLen = RC2_BLOCKLEN; if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; } memcpy(pbData, pTmpKey->IV, RC2_BLOCKLEN); *pwDataLen = RC2_BLOCKLEN; break;
case KP_SALT: if ((CALG_RC2 != pTmpKey->Algid) && (CALG_RC4 != pTmpKey->Algid)) { if ((CALG_DES == pTmpKey->Algid) || (CALG_3DES == pTmpKey->Algid) || (CALG_3DES_112 == pTmpKey->Algid)) { *pwDataLen = 0; dwReturn = ERROR_SUCCESS; goto ErrorExit; } else { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } }
if (pbData == NULL || (*pwDataLen < pTmpKey->cbSaltLen)) { *pwDataLen = pTmpKey->cbSaltLen; if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
CopyMemory(pbData, pTmpKey->rgbSalt, pTmpKey->cbSaltLen); *pwDataLen = pTmpKey->cbSaltLen; break;
case KP_PADDING: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD);
if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; } *((DWORD *) pbData) = PKCS5_PADDING; *pwDataLen = sizeof(DWORD); break;
case KP_MODE: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; } *((DWORD *) pbData) = pTmpKey->Mode; *pwDataLen = sizeof(DWORD); break;
case KP_MODE_BITS: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; } *((DWORD *)pbData) = pTmpKey->ModeBits; *pwDataLen = sizeof(DWORD); break;
case KP_PERMISSIONS: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; } *((DWORD *) pbData) = pTmpKey->Permissions; *pwDataLen = sizeof(DWORD); break;
case KP_ALGID: if (pbData == NULL || *pwDataLen < sizeof(ALG_ID)) { *pwDataLen = sizeof(ALG_ID); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; } *((ALG_ID *) pbData) = pTmpKey->Algid; *pwDataLen = sizeof(ALG_ID); break;
case KP_KEYLEN: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
// ALWAYS report keylen in BITS
if ((HNTAG_TO_HTYPE(hKey) == SIGPUBKEY_HANDLE) || (HNTAG_TO_HTYPE(hKey) == EXCHPUBKEY_HANDLE)) { pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue; if (pBsafePubKey == NULL) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; } *((DWORD *) pbData) = pBsafePubKey->bitlen; } else { switch (pTmpKey->Algid) { #ifdef CSP_USE_DES
case CALG_DES: *((DWORD *) pbData) = (DES_KEYSIZE) * 8; break; #endif
#ifdef CSP_USE_3DES
case CALG_3DES_112: *((DWORD *) pbData) = (DES2_KEYSIZE) * 8; break; case CALG_3DES: *((DWORD *) pbData) = (DES3_KEYSIZE) * 8; break; #endif
default: *((DWORD *) pbData) = pTmpKey->cbKeyLen * 8; } } *pwDataLen = sizeof(DWORD); break;
case KP_BLOCKLEN: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
if ((HNTAG_TO_HTYPE(hKey) == SIGPUBKEY_HANDLE) || (HNTAG_TO_HTYPE(hKey) == EXCHPUBKEY_HANDLE)) { pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue; if (pBsafePubKey == NULL) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; } *(DWORD *)pbData = pBsafePubKey->bitlen; *pwDataLen = sizeof(DWORD); } else { switch (pTmpKey->Algid) { #ifdef CSP_USE_RC2
case CALG_RC2: *((DWORD *) pbData) = RC2_BLOCKLEN * 8; *pwDataLen = sizeof(DWORD); break; #endif
#ifdef CSP_USE_DES
case CALG_DES: *((DWORD *) pbData) = DES_BLOCKLEN * 8; *pwDataLen = sizeof(DWORD); break; #endif
#ifdef CSP_USE_3DES
case CALG_3DES_112: case CALG_3DES: *((DWORD *) pbData) = DES_BLOCKLEN * 8; *pwDataLen = sizeof(DWORD); break; #endif
#ifdef CSP_USE_AES
case CALG_AES_128: case CALG_AES_192: case CALG_AES_256: *((DWORD *) pbData) = pTmpKey->dwBlockLen * 8; *pwDataLen = sizeof(DWORD); break; #endif
default: *((DWORD *) pbData) = 0; *pwDataLen = sizeof(DWORD); } } break;
case KP_EFFECTIVE_KEYLEN: if (CALG_RC2 != pTmpKey->Algid && CALG_DES != pTmpKey->Algid && CALG_3DES != pTmpKey->Algid && CALG_3DES_112 != pTmpKey->Algid) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); if (pbData == NULL) dwReturn = ERROR_SUCCESS; else dwReturn = ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); pdw = (DWORD*)pbData; switch (pTmpKey->Algid) { case CALG_RC2: *pdw = pTmpKey->EffectiveKeyLen; break; case CALG_DES: *pdw = (DES_KEYSIZE - 1) * 8; break; case CALG_3DES_112: *pdw = (DES2_KEYSIZE - 2) * 8; break; case CALG_3DES: *pdw = (DES3_KEYSIZE - 3) * 8; break; } break;
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ DWORD DeletePersistedKey( PNTAGUserList pTmpUser, DWORD dwKeySpec) { DWORD dwReturn = ERROR_INTERNAL_ERROR; CHAR *pszExport; CHAR *pszPrivKey; CHAR *pszPubKey; BOOL fMachineKeySet = FALSE; DWORD dwSts;
if (pTmpUser->Rights & CRYPT_MACHINE_KEYSET) fMachineKeySet = TRUE;
if (AT_SIGNATURE == dwKeySpec) { pszExport = "SExport"; pszPrivKey = "SPvK"; pszPubKey = "SPbK"; } else if (AT_KEYEXCHANGE == dwKeySpec) { pszExport = "EExport"; pszPrivKey = "EPvK"; pszPubKey = "EPbK"; } else { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; }
// if protected store is available then delete the key from there
if (pTmpUser->pPStore) { dwSts = DeleteKeyFromProtectedStorage( pTmpUser, &g_Strings, dwKeySpec, fMachineKeySet, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
// delete stuff from the registry
RegDeleteValue(pTmpUser->hKeys, pszPrivKey); RegDeleteValue(pTmpUser->hKeys, pszPubKey); RegDeleteValue(pTmpUser->hKeys, pszExport);
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
#ifdef USE_SGC
//
// Function to bring all the SGC checking together
//
/*static*/ DWORD SetSGCInfo( PNTAGUserList pTmpUser, CONST BYTE *pbData) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PCCERT_CONTEXT pCertContext = (PCCERT_CONTEXT)pbData; BSAFE_PUB_KEY *pPubKey; BYTE *pbMod; DWORD dwSts;
// make sure the root certs are loaded
dwSts = LoadSGCRoots(&pTmpUser->CritSec); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// verify context means that you are on the client side
if (pTmpUser->Rights & CRYPT_VERIFYCONTEXT) { dwSts = SPQueryCFLevel(pCertContext, NULL, 0, 0, (LPDWORD)&pTmpUser->dwSGCFlags); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// set the modulus of the SGC cert so it may be checked later
// when exporting the pre-master secret
dwSts = SGCAssignPubKey(pCertContext, &pTmpUser->pbSGCKeyMod, &pTmpUser->cbSGCKeyMod, &pTmpUser->dwSGCKeyExpo); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } else { // get a pointer to the exchange public key
if ((0 == pTmpUser->ContInfo.ContLens.cbExchPub) || (NULL == pTmpUser->ContInfo.pbExchPub)) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; }
pPubKey = (BSAFE_PUB_KEY*)pTmpUser->ContInfo.pbExchPub; pbMod = (BYTE*)pPubKey + sizeof(BSAFE_PUB_KEY);
dwSts = SPQueryCFLevel(pCertContext, pbMod, pPubKey->bitlen / 8, pPubKey->pubexp, (LPDWORD)&pTmpUser->dwSGCFlags); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } }
if (0 == pTmpUser->dwSGCFlags) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; } #endif
/*
- CPSetProvParam - * Purpose: * Allows applications to customize various aspects of the * operations of a provider * * Parameters: * IN hUID - Handle to a CSP * IN dwParam - Parameter number * IN pbData - Pointer to data * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPSetProvParam( IN HCRYPTPROV hUID, IN DWORD dwParam, IN CONST BYTE *pbData, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; HCRYPTKEY hKey = 0; BOOL fRet; DWORD dwSts;
EntryPoint pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
switch (dwParam) { case PP_KEYSET_SEC_DESCR: if (0 != (dwFlags & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (!(dwFlags & OWNER_SECURITY_INFORMATION) && !(dwFlags & GROUP_SECURITY_INFORMATION) && !(dwFlags & DACL_SECURITY_INFORMATION) && !(dwFlags & SACL_SECURITY_INFORMATION)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// set the security descriptor for the hKey of the keyset
dwSts = SetSecurityOnContainer(pTmpUser->ContInfo.rgwszFileName, pTmpUser->dwProvType, pTmpUser->Rights & CRYPT_MACHINE_KEYSET, (SECURITY_INFORMATION)dwFlags, (PSECURITY_DESCRIPTOR)pbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case PP_KEY_TYPE_SUBTYPE: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } break;
case PP_UI_PROMPT: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pTmpUser->pPStore) { dwSts = SetUIPrompt(pTmpUser, (LPWSTR)pbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } else { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; } break;
case PP_DELETEKEY: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check if it is a verify context
if (pTmpUser->Rights & CRYPT_VERIFYCONTEXT) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
// check if the keys exists
if (!CPGetUserKey(hUID, *((DWORD*)pbData), &hKey)) { dwReturn = GetLastError(); // (DWORD)NTE_NO_KEY
goto ErrorExit; }
// destroy the key handle right away
if (!CPDestroyKey(hUID, hKey)) { dwReturn = GetLastError(); goto ErrorExit; }
// delete the key
dwSts = DeletePersistedKey(pTmpUser, *(DWORD*)pbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case PP_SGC_INFO: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check if it is an SChannel provider
if (PROV_RSA_SCHANNEL != pTmpUser->dwProvType) { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
#ifdef USE_SGC
// check if the SGC Info (cert) is good
dwSts = SetSGCInfo(pTmpUser, pbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // (DWORD)NTE_FAIL
goto ErrorExit; } #endif
break;
#ifdef USE_HW_RNG
#ifdef _M_IX86
case PP_USE_HARDWARE_RNG: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = GetRNGDriverHandle(&(pTmpUser->hRNGDriver)); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif // _M_IX86
#endif // USE_HW_RNG
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*
- CPGetProvParam - * Purpose: * Allows applications to get various aspects of the * operations of a provider * * Parameters: * IN hUID - Handle to a CSP * IN dwParam - Parameter number * IN pbData - Pointer to data * IN pdwDataLen - Length of parameter data * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPGetProvParam( IN HCRYPTPROV hUID, IN DWORD dwParam, IN BYTE *pbData, IN DWORD *pwDataLen, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; PROV_ENUMALGS *pEnum = NULL; PROV_ENUMALGS_EX *pEnumEx = NULL; DWORD cbName = 0; LPSTR pszName; DWORD cbTmpData; BOOL fRet; DWORD dwSts;
EntryPoint pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if (pwDataLen == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
switch (dwParam) { case PP_ENUMALGS: if (PROV_RSA_SCHANNEL == pTmpUser->dwProvType) { if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT | CRYPT_SGC_ENUM)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } } else { if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } }
pEnumEx = g_AlgTables[pTmpUser->dwCspTypeId];
if (dwFlags & CRYPT_FIRST) pTmpUser->dwEnumalgs = 0; else if (0xFFFFFFFF == pTmpUser->dwEnumalgs) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pEnumEx[pTmpUser->dwEnumalgs].aiAlgid == 0) { dwReturn = ERROR_NO_MORE_ITEMS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(PROV_ENUMALGS)) { *pwDataLen = sizeof(PROV_ENUMALGS); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
// each entry in ENUMALGS is of fixed size
pEnum = (PROV_ENUMALGS *)pbData; pEnum->aiAlgid = pEnumEx[pTmpUser->dwEnumalgs].aiAlgid; pEnum->dwBitLen = pEnumEx[pTmpUser->dwEnumalgs].dwDefaultLen; pEnum->dwNameLen = pEnumEx[pTmpUser->dwEnumalgs].dwNameLen; memcpy(pEnum->szName, pEnumEx[pTmpUser->dwEnumalgs].szName, sizeof(pEnum->szName)); *pwDataLen = sizeof(PROV_ENUMALGS);
pTmpUser->dwEnumalgs++; break;
case PP_ENUMALGS_EX: if (PROV_RSA_SCHANNEL == pTmpUser->dwProvType) { if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT | CRYPT_SGC_ENUM)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } } else { if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } }
pEnumEx = g_AlgTables[pTmpUser->dwCspTypeId];
if (dwFlags & CRYPT_FIRST) pTmpUser->dwEnumalgsEx = 0; else if (0xFFFFFFFF == pTmpUser->dwEnumalgsEx) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pEnumEx[pTmpUser->dwEnumalgsEx].aiAlgid == 0) { dwReturn = ERROR_NO_MORE_ITEMS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(pEnumEx[0])) { *pwDataLen = sizeof(pEnumEx[0]); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
// each entry in ENUMALGSEX is of fixed size
memcpy(pbData, &pEnumEx[pTmpUser->dwEnumalgsEx], sizeof(pEnumEx[0])); *pwDataLen = sizeof(pEnumEx[0]);
pTmpUser->dwEnumalgsEx++; break;
case PP_ENUMCONTAINERS: { BOOL fMachineKeySet = pTmpUser->Rights & CRYPT_MACHINE_KEYSET;
if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT)) != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (dwFlags & CRYPT_FIRST) { if (0 != pTmpUser->ContInfo.hFind) { FindClose(pTmpUser->ContInfo.hFind); pTmpUser->ContInfo.hFind = 0; } FreeEnumOldMachKeyEntries(&pTmpUser->ContInfo); FreeEnumRegEntries(&pTmpUser->ContInfo);
pTmpUser->ContInfo.fCryptFirst = TRUE; pTmpUser->ContInfo.fNoMoreFiles = FALSE; } else if (!pTmpUser->ContInfo.fCryptFirst) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = ERROR_SUCCESS; if (!pTmpUser->ContInfo.fNoMoreFiles) { dwSts = GetNextContainer(pTmpUser->dwProvType, fMachineKeySet, dwFlags, (LPSTR)pbData, pwDataLen, &pTmpUser->ContInfo.hFind); }
// ?BUGBUG? This logic needs desperate cleaning!
if ((ERROR_SUCCESS != dwSts) || pTmpUser->ContInfo.fNoMoreFiles) { if ((ERROR_SUCCESS != dwSts) && (ERROR_NO_MORE_ITEMS != dwSts)) { dwReturn = dwSts; goto ErrorExit; }
pTmpUser->ContInfo.fNoMoreFiles = TRUE;
if (fMachineKeySet) { dwSts = EnumOldMachineKeys(pTmpUser->dwProvType, &pTmpUser->ContInfo); if (ERROR_SUCCESS != dwSts) { if (ERROR_NO_MORE_ITEMS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } } dwSts = EnumRegKeys(&pTmpUser->ContInfo, fMachineKeySet, pTmpUser->dwProvType, pbData, pwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
cbTmpData = *pwDataLen; if ((!fMachineKeySet) || (0 != (dwSts = GetNextEnumedOldMachKeys(&pTmpUser->ContInfo, fMachineKeySet, pbData, &cbTmpData)))) { if (0 != (dwSts = GetNextEnumedRegKeys(&pTmpUser->ContInfo, pbData, pwDataLen))) { dwReturn = dwSts; goto ErrorExit; } } else *pwDataLen = cbTmpData; } break; }
case PP_IMPTYPE: if (0 != dwFlags) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); *((DWORD *) pbData) = CRYPT_IMPL_SOFTWARE; break;
case PP_NAME: if (0 != dwFlags) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
ASSERT(NULL != pTmpUser->szProviderName); if (NULL != pTmpUser->szProviderName) cbName = (lstrlen(pTmpUser->szProviderName) + 1) * sizeof(CHAR); else cbName = 0;
if (pbData == NULL || *pwDataLen < cbName) { *pwDataLen = cbName; dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = cbName; memcpy(pbData, pTmpUser->szProviderName, cbName); break;
case PP_VERSION: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); *((DWORD *) pbData) = 0x200; // ?BUGBUG? Symbolic?
break;
case PP_CONTAINER: if (0 != dwFlags) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
pszName = pTmpUser->ContInfo.pszUserName; if (pbData == NULL || *pwDataLen < (strlen(pszName) + 1)) { *pwDataLen = strlen(pszName) + 1; dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = strlen(pszName) + 1; strcpy((LPSTR)pbData, pszName); break;
case PP_UNIQUE_CONTAINER: if (0 != dwFlags) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = GetUniqueContainerName(&pTmpUser->ContInfo, pbData, pwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case PP_KEYSET_SEC_DESCR: if (0 != (dwFlags & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (!(dwFlags & OWNER_SECURITY_INFORMATION) && !(dwFlags & GROUP_SECURITY_INFORMATION) && !(dwFlags & DACL_SECURITY_INFORMATION) && !(dwFlags & SACL_SECURITY_INFORMATION)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
dwSts = GetSecurityOnContainer(pTmpUser->ContInfo.rgwszFileName, pTmpUser->dwProvType, pTmpUser->Rights & CRYPT_MACHINE_KEYSET, (SECURITY_INFORMATION)dwFlags, (PSECURITY_DESCRIPTOR)pbData, pwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case PP_KEYSTORAGE: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); if (pTmpUser->pPStore) *((DWORD*)pbData) = CRYPT_PSTORE | CRYPT_UI_PROMPT | CRYPT_SEC_DESCR; else *((DWORD*)pbData) = CRYPT_SEC_DESCR; break;
case PP_PROVTYPE: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); *((DWORD*)pbData) = pTmpUser->dwProvType; break;
case PP_KEYSET_TYPE: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); if (pTmpUser->Rights & CRYPT_MACHINE_KEYSET) *(DWORD*)pbData = CRYPT_MACHINE_KEYSET; else *(DWORD*)pbData = 0; break;
case PP_SIG_KEYSIZE_INC: case PP_KEYX_KEYSIZE_INC: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); *((DWORD*)pbData) = RSA_KEYSIZE_INC; break;
case PP_SGC_INFO: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check if it is an SChannel provider
if (PROV_RSA_SCHANNEL != pTmpUser->dwProvType) { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); // return the SGC Flags
#ifdef USE_SGC
*((DWORD*)pbData) = pTmpUser->dwSGCFlags; #else
*((DWORD*)pbData) = 0; #endif
break;
#ifdef USE_HW_RNG
#ifdef _M_IX86
case PP_USE_HARDWARE_RNG: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
*pwDataLen = 0;
// check if the hardware RNG is available for use
dwSts = CheckIfRNGAvailable(); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif // _M_IX86
#endif // USE_HW_RNG
case PP_KEYSPEC: if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); if (PROV_RSA_SIG == pTmpUser->dwProvType) *((DWORD*)pbData) = AT_SIGNATURE; else if (PROV_RSA_FULL == pTmpUser->dwProvType) *((DWORD*)pbData) = AT_SIGNATURE | AT_KEYEXCHANGE; else if (PROV_RSA_SCHANNEL == pTmpUser->dwProvType) *((DWORD*)pbData) = AT_KEYEXCHANGE; break;
case PP_ENUMEX_SIGNING_PROT: if (0 != dwFlags) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
*pwDataLen = 0; break;
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*
- CPSetHashParam - * Purpose: * Allows applications to customize various aspects of the * operations of a hash * * Parameters: * IN hUID - Handle to a CSP * IN hHash - Handle to a hash * IN dwParam - Parameter number * IN pbData - Pointer to data * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPSetHashParam( IN HCRYPTPROV hUID, IN HCRYPTHASH hHash, IN DWORD dwParam, IN CONST BYTE *pbData, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pTmpHash; PNTAGKeyList pTmpKey; MD4_object *pMD4Hash; MD5_object *pMD5Hash; A_SHA_CTX *pSHAHash; MACstate *pMAC; PHMAC_INFO pHMACInfo; BYTE *pb; BOOL fRet; DWORD dwSts;
EntryPoint if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check the user identification
if (NTLCheckList((HNTAG)hUID, USER_HANDLE) == NULL) { 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; }
switch (dwParam) { case HP_HASHVAL: switch (pTmpHash->Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: { MD2_object *pMD2Hash;
pMD2Hash = (MD2_object *) pTmpHash->pHashData; if (pMD2Hash->FinishFlag == TRUE) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
memcpy(&pMD2Hash->MD.state, pbData, MD2DIGESTLEN); break; } #endif
#ifdef CSP_USE_MD4
case CALG_MD4: pMD4Hash = (MD4_object *) pTmpHash->pHashData; if (pMD4Hash->FinishFlag == TRUE) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
memcpy (&pMD4Hash->MD, pbData, MD4DIGESTLEN); break; #endif
#ifdef CSP_USE_MD5
case CALG_MD5: pMD5Hash = (MD5_object *) pTmpHash->pHashData; if (pMD5Hash->FinishFlag == TRUE) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
memcpy (pMD5Hash->digest, pbData, MD5DIGESTLEN); break; #endif
#ifdef CSP_USE_SHA
case CALG_SHA: pSHAHash = (A_SHA_CTX *) pTmpHash->pHashData; if (pSHAHash->FinishFlag == TRUE) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
memcpy (pSHAHash->HashVal, pbData, A_SHA_DIGEST_LEN); break; #endif
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5: memcpy (pTmpHash->pHashData, pbData, SSL3_SHAMD5_LEN); break; #endif
#ifdef CSP_USE_MAC
case CALG_MAC: pMAC = (MACstate *)pTmpHash->pHashData; 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->FinishFlag == TRUE) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
memcpy(pTmpKey->FeedBack, pbData, pTmpKey->dwBlockLen); break; #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } pTmpHash->dwHashState |= DATA_IN_HASH; break;
case HP_HMAC_INFO: if (CALG_HMAC != pTmpHash->Algid) { dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
pHMACInfo = (PHMAC_INFO)pbData; pTmpHash->HMACAlgid = pHMACInfo->HashAlgid;
// now that we know the type of hash we can create it
dwSts = LocalCreateHash(pTmpHash->HMACAlgid, (BYTE**)&pTmpHash->pHashData, &pTmpHash->dwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// if the length of the inner string is 0 then use the default string
if (0 == pHMACInfo->cbInnerString) pTmpHash->cbHMACInner = HMAC_DEFAULT_STRING_LEN; else pTmpHash->cbHMACInner = pHMACInfo->cbInnerString;
pb = _nt_malloc(pTmpHash->cbHMACInner); if (NULL == pb) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
if (0 == pHMACInfo->cbInnerString) memset(pb, 0x36, pTmpHash->cbHMACInner); else memcpy(pb, pHMACInfo->pbInnerString, pTmpHash->cbHMACInner);
if (pTmpHash->pbHMACInner) _nt_free(pTmpHash->pbHMACInner, pTmpHash->cbHMACInner); pTmpHash->pbHMACInner = pb;
// if the length of the outer string is 0 then use the default string
if (0 == pHMACInfo->cbOuterString) pTmpHash->cbHMACOuter = HMAC_DEFAULT_STRING_LEN; else pTmpHash->cbHMACOuter = pHMACInfo->cbOuterString;
pb = _nt_malloc(pTmpHash->cbHMACOuter); if (NULL == pb) { _nt_free(pTmpHash->pbHMACInner, pTmpHash->cbHMACInner); dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
if (0 == pHMACInfo->cbOuterString) memset(pb, 0x5C, pTmpHash->cbHMACOuter); else memcpy(pb, pHMACInfo->pbOuterString, pTmpHash->cbHMACOuter); if (pTmpHash->pbHMACOuter) _nt_free(pTmpHash->pbHMACOuter, pTmpHash->cbHMACOuter); pTmpHash->pbHMACOuter = pb; break;
#ifdef CSP_USE_SSL3
case HP_TLS1PRF_LABEL: case HP_TLS1PRF_SEED: { if (CALG_TLS1PRF != pTmpHash->Algid) { dwReturn = (DWORD)NTE_BAD_HASH; goto ErrorExit; }
dwSts = SetPRFHashParam((PRF_HASH*)pTmpHash->pHashData, dwParam, pbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
pTmpHash->dwHashState |= DATA_IN_HASH; break; } #endif
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
if (dwParam == HP_HASHVAL) pTmpHash->HashFlags |= HF_VALUE_SET;
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ DWORD LocalGetHashVal( IN ALG_ID Algid, IN DWORD dwHashFlags, IN OUT BYTE *pbHashData, OUT BYTE *pbHashVal, OUT DWORD *pcbHashVal) { DWORD dwReturn = ERROR_INTERNAL_ERROR; MD2_object *pMD2Hash; MD4_object *pMD4Hash; MD5_object *pMD5Hash; A_SHA_CTX *pSHAHash;
switch (Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: // make sure there's enough room.
if (pbHashVal == NULL || *pcbHashVal < MD2DIGESTLEN) { *pcbHashVal = MD2DIGESTLEN; dwReturn = (pbHashVal == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
pMD2Hash = (MD2_object *)pbHashData; if ((dwHashFlags & HF_VALUE_SET) == 0) { if (pMD2Hash->FinishFlag == TRUE) { *pcbHashVal = MD2DIGESTLEN; memcpy(pbHashVal, pMD2Hash->MD.state, MD2DIGESTLEN); break; }
// set the finish flag on the hash and
// process what's left in the buffer.
pMD2Hash->FinishFlag = TRUE;
// Finish offthe hash
MD2Final(&pMD2Hash->MD); }
*pcbHashVal = MD2DIGESTLEN; memcpy (pbHashVal, pMD2Hash->MD.state, MD2DIGESTLEN); break; #endif
#ifdef CSP_USE_MD4
case CALG_MD4: // make sure there's enough room.
if (pbHashVal == NULL || *pcbHashVal < MD4DIGESTLEN) { *pcbHashVal = MD4DIGESTLEN; dwReturn = (pbHashVal == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
pMD4Hash = (MD4_object *)pbHashData; if ((dwHashFlags & HF_VALUE_SET) == 0) { if (pMD4Hash->FinishFlag == TRUE) { *pcbHashVal = MD4DIGESTLEN; memcpy(pbHashVal, &pMD4Hash->MD, *pcbHashVal); break; }
// set the finish flag on the hash and
// process what's left in the buffer.
pMD4Hash->FinishFlag = TRUE; if (MD4_SUCCESS != MDupdate(&pMD4Hash->MD, pMD4Hash->Buf, MD4BYTESTOBITS(pMD4Hash->BufLen))) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; } }
*pcbHashVal = MD4DIGESTLEN; memcpy(pbHashVal, &pMD4Hash->MD, *pcbHashVal); break; #endif
#ifdef CSP_USE_MD5
case CALG_MD5: // make sure there's enough room.
if (pbHashVal == NULL || *pcbHashVal < MD5DIGESTLEN) { *pcbHashVal = MD5DIGESTLEN; dwReturn = (pbHashVal == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
pMD5Hash = (MD5_object *)pbHashData; if ((dwHashFlags & HF_VALUE_SET) == 0) { if (pMD5Hash->FinishFlag == TRUE) { *pcbHashVal = MD5DIGESTLEN; memcpy (pbHashVal, pMD5Hash->digest, MD5DIGESTLEN); break; }
// set the finish flag on the hash and
// process what's left in the buffer.
pMD5Hash->FinishFlag = TRUE;
// Finish offthe hash
MD5Final(pMD5Hash); }
*pcbHashVal = MD5DIGESTLEN; memcpy (pbHashVal, pMD5Hash->digest, MD5DIGESTLEN); break; #endif
#ifdef CSP_USE_SHA
case CALG_SHA: // make sure there's enough room.
if (pbHashVal == NULL || *pcbHashVal < A_SHA_DIGEST_LEN) { *pcbHashVal = A_SHA_DIGEST_LEN; dwReturn = (pbHashVal == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
pSHAHash = (A_SHA_CTX *)pbHashData; if ((dwHashFlags & HF_VALUE_SET) == 0) { if (pSHAHash->FinishFlag == TRUE) { *pcbHashVal = A_SHA_DIGEST_LEN; memcpy (pbHashVal, pSHAHash->HashVal, A_SHA_DIGEST_LEN); break; }
// set the finish flag on the hash and
// process what's left in the buffer.
pSHAHash->FinishFlag = TRUE;
// Finish off the hash
A_SHAFinal(pSHAHash, pSHAHash->HashVal); }
*pcbHashVal = A_SHA_DIGEST_LEN; memcpy (pbHashVal, pSHAHash->HashVal, A_SHA_DIGEST_LEN); break; #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
/*static*/ DWORD GetHashLength( IN ALG_ID Algid) { DWORD cbLen;
switch (Algid) { #ifdef CSP_USE_MD2
case CALG_MD2: cbLen = MD2DIGESTLEN; break; #endif
#ifdef CSP_USE_MD4
case CALG_MD4: cbLen = MD4DIGESTLEN; break; #endif
#ifdef CSP_USE_MD5
case CALG_MD5: cbLen = MD5DIGESTLEN; break; #endif
#ifdef CSP_USE_SHA
case CALG_SHA: cbLen = A_SHA_DIGEST_LEN; break; #endif
default: ASSERT(FALSE); cbLen = 0; }
return cbLen; }
/*
- CPGetHashParam - * Purpose: * Allows applications to get various aspects of the * operations of a key * * Parameters: * IN hUID - Handle to a CSP * IN hHash - Handle to a hash * IN dwParam - Parameter number * IN pbData - Pointer to data * IN pdwDataLen - Length of parameter data * IN dwFlags - Flags values * * Returns: */
BOOL WINAPI CPGetHashParam( IN HCRYPTPROV hUID, IN HCRYPTHASH hHash, IN DWORD dwParam, IN BYTE *pbData, IN DWORD *pwDataLen, IN DWORD dwFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGHashList pTmpHash; MACstate *pMAC; BYTE MACbuf[2*MAX_BLOCKLEN]; PNTAGKeyList pTmpKey; BYTE rgbFinalHash[A_SHA_DIGEST_LEN]; DWORD cbFinalHash; DWORD cb; BYTE *pb = NULL; DWORD cbHashData; BYTE *pbHashData = NULL; DWORD i; BOOL fRet; DWORD dwSts;
EntryPoint if (dwFlags != 0) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; }
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; }
if (pwDataLen == NULL) { dwReturn = ERROR_INVALID_PARAMETER; goto ErrorExit; }
dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; }
switch (dwParam) { case HP_ALGID: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
*((DWORD *) pbData) = pTmpHash->Algid; *pwDataLen = sizeof(DWORD); break;
case HP_HASHSIZE: if (pbData == NULL || *pwDataLen < sizeof(DWORD)) { *pwDataLen = sizeof(DWORD); dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
switch (pTmpHash->Algid) { case CALG_MD2: case CALG_MD4: case CALG_MD5: case CALG_SHA: *(DWORD *)pbData = GetHashLength(pTmpHash->Algid); break; #ifdef CSP_USE_MAC
case CALG_MAC: *(DWORD *)pbData = MAX_BLOCKLEN; break; #endif // CSP_USE_MAC
case CALG_HMAC: *(DWORD *)pbData = GetHashLength(pTmpHash->HMACAlgid); break; #ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5: *((DWORD *) pbData) = SSL3_SHAMD5_LEN; break; #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
*pwDataLen = sizeof(DWORD); break;
case HP_HASHVAL: switch (pTmpHash->Algid) { #ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5: // make sure there's enough room.
if (pbData == NULL || *pwDataLen < SSL3_SHAMD5_LEN) { *pwDataLen = SSL3_SHAMD5_LEN; dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
// Hash value must have already been set.
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0) { dwReturn = (DWORD)NTE_BAD_HASH_STATE; goto ErrorExit; }
*pwDataLen = SSL3_SHAMD5_LEN; memcpy (pbData, pTmpHash->pHashData, SSL3_SHAMD5_LEN); break; #endif
#ifdef CSP_USE_MAC
case CALG_MAC: pMAC = (MACstate *)pTmpHash->pHashData; dwSts = NTLValidate(pTmpHash->hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
// make sure there is enough room.
if (pbData == NULL || (*pwDataLen < pTmpKey->dwBlockLen)) { *pwDataLen = pTmpKey->dwBlockLen; dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; }
if (pMAC->FinishFlag == TRUE) { *pwDataLen = pTmpKey->dwBlockLen; memcpy(pbData, pTmpKey->FeedBack, pTmpKey->dwBlockLen); break; }
// set the finish flag on the hash and
// process what's left in the buffer.
pMAC->FinishFlag = TRUE;
if (pMAC->dwBufLen) { memset(MACbuf, 0, 2*MAX_BLOCKLEN); memcpy(MACbuf, pMAC->Buffer, pMAC->dwBufLen);
switch (pTmpKey->Algid) { case CALG_RC2: dwSts = BlockEncrypt(RC2, pTmpKey, RC2_BLOCKLEN, TRUE, MACbuf, &pMAC->dwBufLen, 2*MAX_BLOCKLEN); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break;
case CALG_DES: dwSts = BlockEncrypt(des, pTmpKey, DES_BLOCKLEN, TRUE, MACbuf, &pMAC->dwBufLen, 2*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, TRUE, MACbuf, &pMAC->dwBufLen, 2*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, TRUE, MACbuf, &pMAC->dwBufLen, 2*MAX_BLOCKLEN); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif
// default: It's not a block cipher.
} }
*pwDataLen = pTmpKey->dwBlockLen; memcpy(pbData, pTmpKey->FeedBack, pTmpKey->dwBlockLen); break; #endif
case CALG_HMAC: if (!(pTmpHash->HMACState & HMAC_FINISHED)) { cbFinalHash = sizeof(rgbFinalHash); dwSts = LocalGetHashVal(pTmpHash->HMACAlgid, pTmpHash->HashFlags, pTmpHash->pHashData, rgbFinalHash, &cbFinalHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
// now XOR the outer string with the key and hash
// over this and the inner hash
dwSts = NTLValidate(pTmpHash->hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; }
if (pTmpKey->cbKeyLen < pTmpHash->cbHMACOuter) cb = pTmpHash->cbHMACOuter; else cb = pTmpKey->cbKeyLen;
pb = (BYTE *)_nt_malloc(cb); if (NULL == pb) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pb, pTmpHash->pbHMACOuter, pTmpHash->cbHMACOuter);
// currently no support for byte reversed keys with HMAC
for (i=0;i<pTmpKey->cbKeyLen;i++) pb[i] ^= (pTmpKey->pKeyValue)[i];
dwSts = LocalCreateHash(pTmpHash->HMACAlgid, &pbHashData, &cbHashData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwSts = LocalHashData(pTmpHash->HMACAlgid, pbHashData, pb, cb); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwSts = LocalHashData(pTmpHash->HMACAlgid, pbHashData, rgbFinalHash, cbFinalHash); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
_nt_free(pTmpHash->pHashData, pTmpHash->dwDataLen); pTmpHash->dwDataLen = cbHashData; pTmpHash->pHashData = pbHashData; pbHashData = NULL; pTmpHash->HMACState |= HMAC_FINISHED; }
dwSts = LocalGetHashVal(pTmpHash->HMACAlgid, pTmpHash->HashFlags, pTmpHash->pHashData, pbData, pwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #ifdef CSP_USE_SSL3
case CALG_TLS1PRF: { dwSts = CalculatePRF((PRF_HASH*)pTmpHash->pHashData, pbData, pwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; } #endif
default: dwSts = LocalGetHashVal(pTmpHash->Algid, pTmpHash->HashFlags, pTmpHash->pHashData, pbData, pwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } break;
default: dwReturn = (DWORD)NTE_BAD_TYPE; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (pb) _nt_free(pb, cb); if (pbHashData) _nt_free(pbHashData, cbHashData); if (!fRet) SetLastError(dwReturn); return fRet; }
/*static*/ DWORD CopyKey( IN PNTAGKeyList pOldKey, OUT PNTAGKeyList *ppNewKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGKeyList pNewKey;
pNewKey = (PNTAGKeyList)_nt_malloc(sizeof(NTAGKeyList)); if (NULL == pNewKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pNewKey, pOldKey, sizeof(NTAGKeyList)); pNewKey->Rights &= ~CRYPT_ARCHIVABLE; pNewKey->Permissions &= ~CRYPT_ARCHIVE; pNewKey->pKeyValue = NULL; pNewKey->cbDataLen = 0; pNewKey->pData = NULL; pNewKey->cbSaltLen = 0;
pNewKey->cbKeyLen = pOldKey->cbKeyLen; if (pNewKey->cbKeyLen) { pNewKey->pKeyValue = (BYTE*)_nt_malloc(pNewKey->cbKeyLen); if (NULL == pNewKey->pKeyValue) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } }
memcpy(pNewKey->pKeyValue, pOldKey->pKeyValue, pNewKey->cbKeyLen); pNewKey->cbDataLen = pOldKey->cbDataLen; if (pNewKey->cbDataLen) { pNewKey->pData = (BYTE*)_nt_malloc(pNewKey->cbDataLen); if (NULL == pNewKey->pData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } }
memcpy(pNewKey->pData, pOldKey->pData, pNewKey->cbDataLen); if (pOldKey->Algid == CALG_PCT1_MASTER) { // This is a PCT master key, and so it might have some certificate
// data attached to it. If this is the case, then make a copy
// of the certificate data and attach it to the new key.
if (pOldKey->cbDataLen == sizeof(SCH_KEY)) { PSCH_KEY pOldSChKey = (PSCH_KEY)pOldKey->pData; PSCH_KEY pNewSChKey = (PSCH_KEY)pNewKey->pData;
if (pOldSChKey->pbCertData && pOldSChKey->cbCertData) { pNewSChKey->pbCertData = (BYTE*)_nt_malloc(pOldSChKey->cbCertData); if (NULL == pNewSChKey->pbCertData) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
memcpy(pNewSChKey->pbCertData, pOldSChKey->pbCertData, pOldSChKey->cbCertData); } } }
pNewKey->cbSaltLen = pOldKey->cbSaltLen; memcpy(pNewKey->rgbSalt, pOldKey->rgbSalt, pNewKey->cbSaltLen);
*ppNewKey = pNewKey; pNewKey = NULL; dwReturn = ERROR_SUCCESS;
ErrorExit: if (NULL != pNewKey) FreeNewKey(pNewKey); return dwReturn; }
/*
- CPDuplicateKey - * Purpose: * Duplicates the state of a key and returns a handle to it * * Parameters: * IN hUID - Handle to a CSP * IN hKey - Handle to a key * IN pdwReserved - Reserved * IN dwFlags - Flags * IN phKey - Handle to the new key * * Returns: */
BOOL WINAPI CPDuplicateKey( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN DWORD *pdwReserved, IN DWORD dwFlags, IN HCRYPTKEY *phKey) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGKeyList pTmpKey; PNTAGKeyList pNewKey = NULL; BYTE bType = KEY_HANDLE; 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)hKey, hUID, bType, &pTmpKey); if (ERROR_SUCCESS != dwSts) { bType = SIGPUBKEY_HANDLE; dwSts = NTLValidate((HNTAG)hKey, hUID, bType, &pTmpKey); if (ERROR_SUCCESS != dwSts) { bType = EXCHPUBKEY_HANDLE; dwSts = NTLValidate((HNTAG)hKey, hUID, bType, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; } } }
dwSts = CopyKey(pTmpKey, &pNewKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwSts = NTLMakeItem(phKey, bType, (void *)pNewKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) { if (NULL != pNewKey) FreeNewKey(pNewKey); SetLastError(dwReturn); } return fRet; }
//
// Function : TestEncDec
//
// Description : This function expands the passed in key buffer for the
// appropriate algorithm, and then either encryption or
// decryption is performed. A comparison is then made to see
// if the ciphertext or plaintext matches the expected value.
// The function only uses ECB mode for block ciphers and the
// plaintext buffer must be the same length as the ciphertext
// buffer. The length of the plaintext must be either the
// block length of the cipher if it is a block cipher or less
// than MAX_BLOCKLEN if a stream cipher is being used.
//
/*static*/ DWORD TestEncDec( IN ALG_ID Algid, IN BYTE *pbKey, IN DWORD cbKey, IN BYTE *pbPlaintext, IN DWORD cbPlaintext, IN BYTE *pbCiphertext, IN BYTE *pbIV, IN int iOperation) { DWORD dwReturn = ERROR_INTERNAL_ERROR; BYTE *pbExpandedKey = NULL; BYTE rgbBuffIn[MAX_BLOCKLEN]; BYTE rgbBuffOut[MAX_BLOCKLEN]; DWORD i;
memset(rgbBuffIn, 0, sizeof(rgbBuffIn)); memset(rgbBuffOut, 0, sizeof(rgbBuffOut));
// length of data to encrypt must be < MAX_BLOCKLEN
if (cbPlaintext > MAX_BLOCKLEN) { dwReturn = (DWORD)NTE_BAD_LEN; goto ErrorExit; }
// alloc for and expand the key
switch (Algid) { #ifdef CSP_USE_RC4
case (CALG_RC4): pbExpandedKey = _nt_malloc(sizeof(RC4_KEYSTRUCT)); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
rc4_key((RC4_KEYSTRUCT*)pbExpandedKey, cbKey, pbKey); break; #endif // CSP_USE_RC4
#ifdef CSP_USE_RC2
case (CALG_RC2): pbExpandedKey = _nt_malloc(RC2_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
RC2KeyEx((WORD*)pbExpandedKey, pbKey, cbKey, cbKey * 8); break; #endif // CSP_USE_RC2
#ifdef CSP_USE_DES40
case (CALG_DES40): pbExpandedKey = _nt_malloc(DES_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
pbKey[0] &= 0x0F; // set 4 leftmost bits of first byte to zero
pbKey[2] &= 0x0F; // set 4 leftmost bits of third byte to zero
pbKey[4] &= 0x0F; // set 4 leftmost bits of fifth byte to zero
pbKey[6] &= 0x0F; // set 4 leftmost bits of seventh byte to zero
desparityonkey(pbKey, cbKey); deskey((DESTable*)pbExpandedKey, pbKey); break; #endif // CSP_USE_DES40
#ifdef CSP_USE_DES
case (CALG_DES): pbExpandedKey = _nt_malloc(DES_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
desparityonkey(pbKey, cbKey); deskey((DESTable*)pbExpandedKey, pbKey); break; #endif // CSP_USE_DES
#ifdef CSP_USE_3DES
case (CALG_3DES): pbExpandedKey = _nt_malloc(DES3_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
desparityonkey(pbKey, cbKey); tripledes3key((PDES3TABLE)pbExpandedKey, pbKey); break;
case (CALG_3DES_112): pbExpandedKey = _nt_malloc(DES3_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
desparityonkey(pbKey, cbKey); tripledes2key((PDES3TABLE)pbExpandedKey, pbKey); break; #endif // CSP_USE_3DES
#ifdef CSP_USE_AES
case CALG_AES_128: pbExpandedKey = _nt_malloc(AES_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
aeskey((AESTable *) pbExpandedKey, pbKey, CRYPT_AES128_ROUNDS); break;
case CALG_AES_192: pbExpandedKey = _nt_malloc(AES_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
aeskey((AESTable *) pbExpandedKey, pbKey, CRYPT_AES192_ROUNDS); break;
case CALG_AES_256: pbExpandedKey = _nt_malloc(AES_TABLESIZE); if (NULL == pbExpandedKey) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; }
aeskey((AESTable *) pbExpandedKey, pbKey, CRYPT_AES256_ROUNDS); break; #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
// if encrypting and there is an IV then use it
if ((ENCRYPT == iOperation) && (CALG_RC4 != Algid)) { memcpy(rgbBuffIn, pbPlaintext, cbPlaintext);
if (NULL != pbIV) { for (i = 0; i < cbPlaintext; i++) rgbBuffIn[i] = (BYTE)(rgbBuffIn[i] ^ pbIV[i]); } }
// encrypt the plaintext
switch (Algid) { #ifdef CSP_USE_RC4
case (CALG_RC4): if (ENCRYPT == iOperation) memcpy(rgbBuffOut, pbPlaintext, cbPlaintext); else memcpy(rgbBuffOut, pbCiphertext, cbPlaintext); rc4((RC4_KEYSTRUCT*)pbExpandedKey, cbPlaintext, rgbBuffOut); break; #endif // CSP_USE_RC4
#ifdef CSP_USE_RC2
case (CALG_RC2): if (ENCRYPT == iOperation) RC2(rgbBuffOut, rgbBuffIn, pbExpandedKey, ENCRYPT); else RC2(rgbBuffOut, pbCiphertext, pbExpandedKey, DECRYPT); break; #endif // CSP_USE_RC2
#ifdef CSP_USE_DES40
case (CALG_DES40): if (ENCRYPT == iOperation) des(rgbBuffOut, rgbBuffIn, pbExpandedKey, ENCRYPT); else des(rgbBuffOut, pbCiphertext, pbExpandedKey, DECRYPT); break; #endif // CSP_USE_DES40
#ifdef CSP_USE_DES
case (CALG_DES): if (ENCRYPT == iOperation) des(rgbBuffOut, rgbBuffIn, pbExpandedKey, ENCRYPT); else des(rgbBuffOut, pbCiphertext, pbExpandedKey, DECRYPT); break; #endif // CSP_USE_DES
#ifdef CSP_USE_3DES
case (CALG_3DES): case (CALG_3DES_112): if (ENCRYPT == iOperation) tripledes(rgbBuffOut, rgbBuffIn, pbExpandedKey, ENCRYPT); else tripledes(rgbBuffOut, pbCiphertext, pbExpandedKey, DECRYPT); break; #endif // CSP_USE_3DES
#ifdef CSP_USE_AES
case CALG_AES_128: case CALG_AES_192: case CALG_AES_256: if (ENCRYPT == iOperation) aes(rgbBuffOut, rgbBuffIn, pbExpandedKey, ENCRYPT); else aes(rgbBuffOut, pbCiphertext, pbExpandedKey, DECRYPT); break; #endif
default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; }
if (ENCRYPT == iOperation) { // compare the encrypted plaintext with the passed in ciphertext
if (0 != memcmp(pbCiphertext, rgbBuffOut, cbPlaintext)) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; } } else { // if there is an IV then use it
if (NULL != pbIV) { for (i = 0; i < cbPlaintext; i++) rgbBuffOut[i] = (BYTE)(rgbBuffOut[i] ^ pbIV[i]); }
// compare the decrypted ciphertext with the passed in plaintext
if (0 != memcmp(pbPlaintext, rgbBuffOut, cbPlaintext)) { dwReturn = (DWORD)NTE_FAIL; goto ErrorExit; } }
dwReturn = ERROR_SUCCESS;
ErrorExit: if (pbExpandedKey) _nt_free(pbExpandedKey, 0); return dwReturn; }
//
// Function : TestSymmetricAlgorithm
//
// Description : This function expands the passed in key buffer for the
// appropriate algorithm, encrypts the plaintext buffer with the
// same algorithm and key, and the compares the passed in
// expected ciphertext with the calculated ciphertext to make
// sure they are the same. The opposite is then done with
// decryption.
//
// The function only uses ECB mode for block ciphers and the
// plaintext buffer must be the same length as the ciphertext
// buffer. The length of the plaintext must be either the block
// length of the cipher if it is a block cipher or less than
// MAX_BLOCKLEN if a stream cipher is being used.
//
DWORD TestSymmetricAlgorithm( IN ALG_ID Algid, IN BYTE *pbKey, IN DWORD cbKey, IN BYTE *pbPlaintext, IN DWORD cbPlaintext, IN BYTE *pbCiphertext, IN BYTE *pbIV) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD dwSts;
dwSts = TestEncDec(Algid, pbKey, cbKey, pbPlaintext, cbPlaintext, pbCiphertext, pbIV, ENCRYPT); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } dwSts = TestEncDec(Algid, pbKey, cbKey, pbPlaintext, cbPlaintext, pbCiphertext, pbIV, DECRYPT); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; }
dwReturn = ERROR_SUCCESS;
ErrorExit: return dwReturn; }
|