Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6773 lines
186 KiB

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