Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3382 lines
100 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 //
// //
// Copyright (C) 1993 Microsoft Corporation All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "nt_rsa.h"
#include "nt_blobs.h"
#include "swnt_pk.h"
#include "vectest.h"
#include "mac.h"
#ifdef STT
#include "prodname.h"
#include "ntagimp1.h"
#include "sttalgid.h"
#endif //STT
#include "ntagum.h"
const struct enumalgs {
ALG_ID aiAlgid;
DWORD dwBitLen;
DWORD dwNameLen;
CHAR szName[20];
} ENUMALGS[] =
{
// ALGID BitLen NameLen szName
#ifdef CSP_USE_RC2
CALG_RC2, 40, 4, "RC2",
#endif
#ifdef CSP_USE_RC4
CALG_RC4, 40, 4, "RC4",
#endif
#ifdef CSP_USE_DES
CALG_DES, 56, 4, "DES",
#endif
#ifdef CSP_USE_SHA
CALG_SHA, 160, 4, "SHA",
#endif
#ifdef CSP_USE_MD2
CALG_MD2, 128, 4, "MD2",
#endif
#ifdef CSP_USE_MD4
CALG_MD4, 128, 4, "MD4",
#endif
#ifdef CSP_USE_MD5
CALG_MD5, 128, 4, "MD5",
#endif
#ifdef CSP_USE_MAC
CALG_MAC, 64, 4, "MAC",
#endif
CALG_RSA_SIGN, 512, 9, "RSA_SIGN",
CALG_RSA_KEYX, 512, 9, "RSA_KEYX",
0, 0, 0, 0
};
#ifndef STT
#define NTAG_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\UserKeys"
#define NTAG_MACH_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\MachineKeys"
#else
#define NTAG_REG_KEY_LOC "Software\\Microsoft\\" PRODUCT_NAME "\\" KEY_LOCATION
#endif //STT
BOOL BlockEncrypt(void EncFun(BYTE *In, BYTE *Out, void *key, int op),
PNTAGKeyList pKey,
int BlockLen,
BOOL Final,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwBufLen);
/* MakeNewKey
*
* Helper routine for ImportKey, GenKey
*
* Allocate a new key record, fill in the data and copy in the key
* bytes.
*/
PNTAGKeyList MakeNewKey(
ALG_ID aiKeyAlg,
DWORD dwRights,
DWORD wKeyLen,
HCRYPTPROV hUID,
CONST BYTE *pbKeyData
)
{
PNTAGKeyList pKey;
BSAFE_PUB_KEY *pPubKey;
// allocate space for the key record
if ((pKey = (PNTAGKeyList)_nt_malloc(sizeof(NTAGKeyList))) == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
if ((pKey->pKeyValue = (BYTE *)_nt_malloc((size_t)wKeyLen)) == NULL)
{
_nt_free (pKey, sizeof(NTAGKeyList));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
pKey->Algid = aiKeyAlg;
pKey->Rights = dwRights;
pKey->cbDataLen = 0;
#ifdef STT
pKey->cbInfo = 0;
#endif
pKey->pData = NULL;
pKey->hUID = hUID;
memset(pKey->IV, 0, CRYPT_BLKLEN);
memset(pKey->FeedBack, 0, CRYPT_BLKLEN);
pKey->InProgress = FALSE;
memset(pKey->Salt, 0, SALT_LENGTH);
pKey->Padding = PKCS5_PADDING;
pKey->Mode = CRYPT_MODE_CBC;
pKey->ModeBits = 0;
pKey->Permissions = 0xffffffff;
pKey->cbKeyLen = wKeyLen;
if (pbKeyData != NULL)
{
memcpy (pKey->pKeyValue, pbKeyData, (size_t)wKeyLen);
}
pPubKey = (BSAFE_PUB_KEY *) pKey->pKeyValue;
return pKey;
}
/* FreeNewKey
*
* Use for cleanup on abort of key build operations.
*
*/
void FreeNewKey(PNTAGKeyList pOldKey)
{
_nt_free(pOldKey->pKeyValue, pOldKey->cbKeyLen);
_nt_free(pOldKey, sizeof(NTAGKeyList));
}
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;
/* PreparePrivateKeyForExport
*
* Massage the key from the registry
* into an exportable format.
*
*/
BOOL PreparePrivateKeyForExport(
IN BSAFE_PRV_KEY *pPrvKey,
IN DWORD PrvKeyLen,
OUT PBYTE pbBlob,
IN OUT PDWORD pcbBlob
)
{
PEXPORT_PRV_KEY pExportKey;
DWORD cbHalfModLen;
DWORD cbBlobLen;
PBYTE pbIn;
PBYTE pbOut;
cbHalfModLen = pPrvKey->bitlen / 16;
cbBlobLen = sizeof(EXPORT_PRV_KEY) + 9 * cbHalfModLen;
if (NULL == pbBlob)
{
*pcbBlob = cbBlobLen;
return TRUE;
}
if (*pcbBlob < cbBlobLen)
{
*pcbBlob = cbBlobLen;
return FALSE;
}
else
{
// 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, cbHalfModLen * 2);
pbIn += (cbHalfModLen + sizeof(DWORD)) * 2;
pbOut += cbHalfModLen * 2;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbIn += cbHalfModLen + sizeof(DWORD);
pbOut += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbIn += cbHalfModLen + sizeof(DWORD);
pbOut += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbIn += cbHalfModLen + sizeof(DWORD);
pbOut += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbIn += cbHalfModLen + sizeof(DWORD);
pbOut += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbIn += cbHalfModLen + sizeof(DWORD);
pbOut += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
}
*pcbBlob = cbBlobLen;
return TRUE;
}
/* PreparePrivateKeyForImport
*
* Massage the incoming into a form acceptable for
* the registry.
*
*/
BOOL PreparePrivateKeyForImport(
IN PBYTE pbBlob,
IN DWORD cbBlob,
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;
if (RSA2 != pExportKey->magic)
return FALSE;
cbHalfModLen = pExportKey->bitlen / 16;
cbPub = sizeof(BSAFE_PUB_KEY) + (cbHalfModLen + sizeof(DWORD)) * 2;
cbPrv = sizeof(BSAFE_PRV_KEY) + (cbHalfModLen + sizeof(DWORD)) * 10;
if ((NULL == pPrvKey) || (NULL == pPubKey))
{
*pPubKeyLen = cbPub;
*pPrvKeyLen = cbPrv;
return TRUE;
}
if ((*pPubKeyLen < cbPub) || (*pPrvKeyLen < cbPrv))
{
*pPubKeyLen = cbPub;
*pPrvKeyLen = cbPrv;
return FALSE;
}
else
{
// form the public key
ZeroMemory(pPubKey, *pPubKeyLen);
pPubKey->magic = RSA1;
pPubKey->keylen = (cbHalfModLen + sizeof(DWORD)) * 2;
pPubKey->bitlen = pExportKey->bitlen;
pPubKey->datalen = cbHalfModLen * 2 - 1;
pPubKey->pubexp = pExportKey->pubexp;
pbIn = pbBlob + sizeof(EXPORT_PRV_KEY);
pbOut = (PBYTE)pPubKey + sizeof(BSAFE_PUB_KEY);
CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
// form the private key
ZeroMemory(pPrvKey, *pPrvKeyLen);
pPrvKey->magic = pExportKey->magic;
pPrvKey->keylen = (cbHalfModLen + sizeof(DWORD)) * 2;
pPrvKey->bitlen = pExportKey->bitlen;
pPrvKey->datalen = cbHalfModLen * 2 - 1;
pPrvKey->pubexp = pExportKey->pubexp;
pbOut = (PBYTE)pPrvKey + sizeof(BSAFE_PRV_KEY);
CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
pbOut += (cbHalfModLen + sizeof(DWORD)) * 2;
pbIn += cbHalfModLen * 2;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbOut += cbHalfModLen + sizeof(DWORD);
pbIn += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbOut += cbHalfModLen + sizeof(DWORD);
pbIn += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbOut += cbHalfModLen + sizeof(DWORD);
pbIn += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbOut += cbHalfModLen + sizeof(DWORD);
pbIn += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen);
pbOut += cbHalfModLen + sizeof(DWORD);
pbIn += cbHalfModLen;
CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
}
*pPubKeyLen = cbPub;
*pPrvKeyLen = cbPrv;
return TRUE;
}
/*
- 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 CPGenKey(IN HCRYPTPROV hUID,
IN ALG_ID Algid,
IN DWORD dwFlags,
OUT HCRYPTKEY * phKey)
{
PNTAGUserList pTmpUser;
PNTAGKeyList pTmpKey;
DWORD dwRights = 0;
BYTE pbRandom[RC2_KEYSIZE];
int localAlgid;
DWORD dwAlgSize;
if ((dwFlags & ~(CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED |
VECTTEST | DES_TEST | CRYPT_CREATE_SALT
#ifdef TEST_VERSION
| KEY_1024
#endif
)) != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
switch (Algid)
{
case AT_KEYEXCHANGE:
localAlgid = CALG_RSA_KEYX;
break;
case AT_SIGNATURE:
#ifndef BBN
localAlgid = CALG_RSA_SIGN;
#else
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
#endif
break;
default:
localAlgid = Algid;
break;
}
if ((pTmpUser = (PNTAGUserList) NTLCheckList (hUID, USER_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if (pTmpUser->Rights & CRYPT_VERIFYCONTEXT)
{
SetLastError((DWORD) NTE_PERM);
return NTF_FAILED;
}
// determine which crypt algorithm is to be used
switch (localAlgid)
{
#ifdef CSP_USE_RC2
case CALG_RC2:
dwAlgSize = RC2_KEYSIZE;
goto gensymkey;
#endif
#ifdef CSP_USE_RC4
case CALG_RC4:
dwAlgSize = RC4_KEYSIZE;
goto gensymkey;
#endif
#ifdef CSP_USE_DES
case CALG_DES:
dwAlgSize = DES_KEYSIZE;
goto gensymkey;
#endif
gensymkey:
if (dwFlags & VECTTEST)
{
switch(localAlgid)
{
#ifdef CSP_USE_RC2
case CALG_RC2:
memcpy(pbRandom, VTRC2, dwAlgSize);
break;
#endif
#ifdef CSP_USE_RC4
case CALG_RC4:
memcpy(pbRandom, VTRC4, dwAlgSize);
break;
#endif
}
}
#ifdef CSP_USE_DES
else if (dwFlags & DES_TEST)
{
switch(localAlgid)
{
case CALG_DES:
memcpy(pbRandom, DESTEST, dwAlgSize);
break;
default:
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
break;
}
}
#endif
else
{
// generate the random key
if (GenRandom(hUID, pbRandom, dwAlgSize) == NTF_FAILED)
{
SetLastError((DWORD) NTE_FAIL);
return NTF_FAILED;
}
if (CALG_DES == localAlgid)
{
//UNDONE: PARITY BIT SETTING ....
}
}
// check if the key is CRYPT_EXPORTABLE
if (dwFlags & CRYPT_EXPORTABLE)
dwRights = CRYPT_EXPORTABLE;
pTmpKey = MakeNewKey(localAlgid, dwRights, dwAlgSize, hUID,
pbRandom);
if (pTmpKey == NULL)
return NTF_FAILED; // error already set
if (dwFlags & CRYPT_CREATE_SALT)
{
if (GenRandom(hUID, pTmpKey->Salt, TOTAL_KEY_SIZE-dwAlgSize) ==
NTF_FAILED)
{
SetLastError((DWORD) NTE_FAIL);
FreeNewKey(pTmpKey);
return NTF_FAILED;
}
}
if (NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey) == NTF_FAILED)
{
FreeNewKey(pTmpKey);
return NTF_FAILED; // error already set
}
break;
case CALG_RSA_KEYX:
case CALG_RSA_SIGN:
{
DWORD bits;
#ifdef TEST_VERSION
bits = (dwFlags & KEY_1024) ? 1024 : 512;
#else
#ifndef STT
bits = 512;
#else
bits = (localAlgid == CALG_RSA_KEYX) ? (RSAEXCHMODLEN * 8) :
(RSASIGNMODLEN * 8);
#endif
#endif
if(NTF_SUCCEED != ReGenKey(hUID, (localAlgid == CALG_RSA_KEYX) ?
NTPK_USE_EXCH : NTPK_USE_SIG,
phKey, bits))
{
return NTF_FAILED;
}
}
if (!RemovePublicKeyExportability(pTmpUser,
(localAlgid == CALG_RSA_KEYX) ?
TRUE : FALSE))
{
return NTF_FAILED;
}
if (dwFlags & CRYPT_EXPORTABLE)
{
if (!MakePublicKeyExportable(pTmpUser,
(localAlgid == CALG_RSA_KEYX) ?
TRUE : FALSE))
{
return NTF_FAILED;
}
}
break;
default:
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
break;
}
if (dwFlags & CRYPT_USER_PROTECTED)
{
if (CryptUserProtectKey(pTmpUser->hPrivuid, *phKey) == CPPAPI_FAILED)
{
return NTF_FAILED;
}
}
return NTF_SUCCEED;
}
/*
- 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 CPDeriveKey(IN HCRYPTPROV hUID,
IN ALG_ID Algid,
IN HCRYPTHASH hBaseData,
IN DWORD dwFlags,
OUT HCRYPTKEY * phKey)
{
PNTAGUserList pTmpUser;
PNTAGKeyList pTmpKey;
DWORD dwRights = 0, dwKeySize;
BYTE pbRandom[RC2_KEYSIZE];
BYTE BaseVal[NT_HASH_BYTES];
PNTAGHashList pTmpHash;
DWORD temp;
if ((dwFlags & ~(CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED |
CRYPT_CREATE_SALT)) != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
if ((pTmpUser = (PNTAGUserList) NTLCheckList (hUID, USER_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if (pTmpUser->Rights & CRYPT_VERIFYCONTEXT)
{
SetLastError((DWORD) NTE_PERM);
return NTF_FAILED;
}
if ((pTmpHash = (PNTAGHashList) NTLValidate(hBaseData, hUID,
HASH_HANDLE)) == NULL)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
if (GetLastError() == NTE_FAIL)
{
SetLastError((DWORD) NTE_BAD_HASH);
}
return NTF_FAILED;
}
if (pTmpHash->HashFlags & HF_VALUE_SET)
{
SetLastError((DWORD) NTE_BAD_HASH);
return NTF_FAILED;
}
memset(BaseVal, 0, NT_HASH_BYTES);
temp = NT_HASH_BYTES;
if (!CPGetHashParam(hUID, hBaseData, HP_HASHVAL, BaseVal, &temp, 0))
{
return NTF_FAILED;
}
switch (Algid)
{
#ifdef CSP_USE_RC2
case CALG_RC2:
dwKeySize = RC2_KEYSIZE;
goto dersymkey;
#endif
#ifdef CSP_USE_RC4
case CALG_RC4:
dwKeySize = RC4_KEYSIZE;
goto dersymkey;
#endif
#ifdef CSP_USE_DES
case CALG_DES:
dwKeySize = DES_KEYSIZE;
goto dersymkey;
#endif
dersymkey:
memcpy(pbRandom, BaseVal, dwKeySize);
// check if the key is CRYPT_EXPORTABLE
if (dwFlags & CRYPT_EXPORTABLE)
dwRights = CRYPT_EXPORTABLE;
pTmpKey = MakeNewKey(Algid, dwRights, dwKeySize, hUID, pbRandom);
if (pTmpKey == NULL)
{
return NTF_FAILED;
}
if (dwFlags & CRYPT_CREATE_SALT)
memcpy(pTmpKey->Salt, BaseVal+dwKeySize,
TOTAL_KEY_SIZE - dwKeySize);
if (NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey) == NTF_FAILED)
{
FreeNewKey(pTmpKey);
return NTF_FAILED; // error already set
}
break;
default:
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
break;
}
if (dwFlags & CRYPT_USER_PROTECTED)
{
if (CryptUserProtectKey(pTmpUser->hPrivuid, *phKey) == CPPAPI_FAILED)
{
return NTF_FAILED;
}
}
return NTF_SUCCEED;
}
/*
- 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 CPExportKey(IN HCRYPTPROV hUID,
IN HCRYPTKEY hKey,
IN HCRYPTKEY hPubKey,
IN DWORD dwBlobType,
IN DWORD dwFlags,
OUT BYTE *pbData,
OUT DWORD *pdwDataLen)
{
// 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;
DWORD PrvKeyLen;
BSAFE_PUB_KEY *pTmpPubKey;
BSAFE_PRV_KEY *pTmpPrvKey;
DWORD cbPrivateBlob = 0;
PBYTE pbPrivateBlob = NULL;
// temporary variables for pointing to user and key records
PNTAGKeyList pTmpKey;
PNTAGKeyList pPubKey;
PNTAGUserList pTmpUser;
if (dwFlags != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
if (pdwDataLen == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NTF_FAILED;
}
if (dwBlobType == PUBLICKEYBLOB && hPubKey != 0)
{
SetLastError((DWORD) NTE_BAD_PUBLIC_KEY);
return NTF_FAILED;
}
// check the user identification
if ((pTmpUser = (PNTAGUserList) NTLCheckList (hUID, USER_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if (CryptConfirmExportKey(pTmpUser->hPrivuid, hKey) == CPPAPI_FAILED)
{
return NTF_FAILED;
}
// 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;
pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey, hUID,
HNTAG_TO_HTYPE(hKey));
if (pTmpKey == NULL)
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
if (dwBlobType != PUBLICKEYBLOB &&
((pTmpKey->Rights & CRYPT_EXPORTABLE) != CRYPT_EXPORTABLE))
{
SetLastError((DWORD) NTE_BAD_KEY_STATE);
return NTF_FAILED;
}
pPreHeader->aiKeyAlg = pTmpKey->Algid;
switch(dwBlobType)
{
case PUBLICKEYBLOB:
{
if ((HNTAG_TO_HTYPE(hKey) != SIGPUBKEY_HANDLE) &&
(HNTAG_TO_HTYPE(hKey) != EXCHPUBKEY_HANDLE))
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue;
if (pBsafePubKey == NULL)
{
SetLastError((DWORD) NTE_NO_KEY);
return NTF_FAILED;
}
//
// Subtract off 2 extra DWORD needed by RSA code
//
dwLen = sizeof(BLOBHEADER) +
sizeof(RSAPUBKEY) +
pBsafePubKey->keylen - 2*sizeof(DWORD);
// Check user buffer size
if (pbData == NULL || *pdwDataLen < dwLen)
{
*pdwDataLen = dwLen;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
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->keylen - 2*sizeof(DWORD));
break;
}
case PRIVATEKEYBLOB:
{
DWORD dwBlockLen = 0;
DWORD cb = sizeof(DWORD);
if (HNTAG_TO_HTYPE(hKey) == SIGPUBKEY_HANDLE)
{
if (!CheckPublicKeyExportability(pTmpUser, FALSE))
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
pPublicKey = (BSAFE_PUB_KEY*)pTmpUser->pSigPubKey;
PubKeyLen = pTmpUser->SigPubLen;
pPrvKey = (BSAFE_PRV_KEY*)pTmpUser->pSigPrivKey;
PrvKeyLen = pTmpUser->SigPrivLen;
}
else if (HNTAG_TO_HTYPE(hKey) == EXCHPUBKEY_HANDLE)
{
if (!CheckPublicKeyExportability(pTmpUser, TRUE))
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
pPublicKey = (BSAFE_PUB_KEY*)pTmpUser->pExchPubKey;
PubKeyLen = pTmpUser->ExchPubLen;
pPrvKey = (BSAFE_PRV_KEY*)pTmpUser->pExchPrivKey;
PrvKeyLen = pTmpUser->ExchPrivLen;
}
else
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
if ((pPublicKey == NULL) || (pPrvKey == NULL))
{
SetLastError((DWORD) NTE_NO_KEY);
return NTF_FAILED;
}
if ((PubKeyLen != pTmpKey->cbKeyLen)||
memcmp((PBYTE)pPublicKey, pTmpKey->pKeyValue, PubKeyLen))
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
dwLen = 0;
if (hPubKey)
{
if (!CPGetKeyParam(hUID, hPubKey, KP_BLOCKLEN,
(PBYTE)&dwBlockLen, &cb, 0))
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
// convert to byte count
dwBlockLen /= 8;
}
if (!PreparePrivateKeyForExport(pPrvKey, PrvKeyLen, NULL, &cbPrivateBlob))
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
dwLen += sizeof(BLOBHEADER) + cbPrivateBlob + dwBlockLen;
// allocate memory for the private key blob
cb = cbPrivateBlob + dwBlockLen;
if (NULL == (pbPrivateBlob = _nt_malloc(cb)))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
if (!PreparePrivateKeyForExport(pPrvKey, PrvKeyLen, pbPrivateBlob, &cbPrivateBlob))
{
memnuke(pbPrivateBlob, cb);
_nt_free(pbPrivateBlob, cb);
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
if (hPubKey)
{
if (!CPEncrypt(hUID, hPubKey, 0, TRUE, 0, pbPrivateBlob,
&cbPrivateBlob, cb))
{
memnuke(pbPrivateBlob, cb);
_nt_free(pbPrivateBlob, cb);
return NTF_FAILED;
}
dwLen = sizeof(BLOBHEADER) + cbPrivateBlob;
}
// Check user buffer size
if (pbData == NULL || *pdwDataLen < dwLen)
{
*pdwDataLen = dwLen;
if (pbData == NULL)
{
if (hPubKey)
{
memnuke(pbPrivateBlob, cb);
_nt_free(pbPrivateBlob, cb);
}
return NTF_SUCCEED;
}
memnuke(pbPrivateBlob, cb);
_nt_free(pbPrivateBlob, cb);
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
CopyMemory(pbData + sizeof(BLOBHEADER), pbPrivateBlob, cbPrivateBlob);
memnuke(pbPrivateBlob, cb);
_nt_free(pbPrivateBlob, cb);
break;
}
case SIMPLEBLOB:
{
if (HNTAG_TO_HTYPE(hKey) != KEY_HANDLE)
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
if ((pPubKey = (PNTAGKeyList) NTLValidate((HNTAG)hPubKey,
hUID,
EXCHPUBKEY_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
pBsafePubKey = (BSAFE_PUB_KEY *) pPubKey->pKeyValue;
if (pBsafePubKey == NULL)
{
SetLastError((DWORD) NTE_NO_KEY);
return NTF_FAILED;
}
//
// Subtract off 8 bytes for 2 extra DWORD needed by RSA code
//
dwLen = sizeof(BLOBHEADER) + sizeof(NTSimpleBlob) +
pBsafePubKey->keylen - 8;
if (pbData == NULL || *pdwDataLen < dwLen)
{
*pdwDataLen = dwLen; // set what we need
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
pSimpleHeader = (NTSimpleBlob *) (pbData + sizeof(BLOBHEADER));
pSimpleHeader->aiEncAlg = CALG_RSA_KEYX;
#ifndef STT
// create a PKCS#1 block type 2 encryption.
if (!PKCS2Encrypt(hUID,
pBsafePubKey, pTmpKey->pKeyValue,
pTmpKey->cbKeyLen,
pbData+sizeof(BLOBHEADER)+sizeof(NTSimpleBlob)))
{
return NTF_FAILED;
}
#else //STT
if(pTmpKey->Algid != CALG_RC4 && pTmpKey->Algid != CALG_DES
#ifdef TEST_VERSION
&& pTmpKey->Algid != CALG_RC2
#endif //TEST_VERSION
)
{
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
}
if (!FOAEncrypt(hUID, pBsafePubKey, pTmpKey,
pbData+sizeof(BLOBHEADER)+sizeof(NTSimpleBlob)))
{
return NTF_FAILED;
}
#endif //STT
break;
}
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
}
// set the size of the key blob
*pdwDataLen = dwLen;
return NTF_SUCCEED;
}
/*
- 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 CPImportKey(IN HCRYPTPROV hUID,
IN CONST BYTE *pbData,
IN DWORD dwDataLen,
IN HCRYPTKEY hPubKey,
IN DWORD dwFlags,
OUT HCRYPTKEY *phKey)
{
// miscellaneous variables
DWORD count = 0, KeyBufLen;
CONST BYTE *pbEncPortion;
BLOBHEADER *ThisStdHeader = (BLOBHEADER *)pbData;
BSAFE_PRV_KEY *pBsafePrvKey;
BYTE KeyBuf[CRYPT_BLKLEN];
// temporary variables for pointing to user and key records
PNTAGUserList pTmpUser;
PNTAGKeyList pTmpKey;
// Validate user pointer
count = *phKey;
if ((dwFlags & ~(CRYPT_USER_PROTECTED || CRYPT_EXPORTABLE)) != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
if (ThisStdHeader->bType != PRIVATEKEYBLOB && hPubKey != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NTF_FAILED;
}
// check the user identification
if ((pTmpUser = (PNTAGUserList) NTLCheckList ((HNTAG)hUID,
USER_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if (pTmpUser->Rights & CRYPT_VERIFYCONTEXT &&
ThisStdHeader->bType != PUBLICKEYBLOB)
{
SetLastError((DWORD) NTE_PERM);
return NTF_FAILED;
}
if (ThisStdHeader->bVersion != CUR_BLOB_VERSION)
{
SetLastError((DWORD) NTE_BAD_VER);
return NTF_FAILED;
}
// Handy pointer for decrypting the blob...
pbEncPortion = pbData+sizeof(BLOBHEADER)+sizeof(NTSimpleBlob);
// determine which key blob is being imported
switch (ThisStdHeader->bType)
{
case PUBLICKEYBLOB:
{
BLOBHEADER *pPublic = (BLOBHEADER *) pbData;
RSAPUBKEY *pImpPubKey =
(RSAPUBKEY *)(pbData+sizeof(BLOBHEADER));
BSAFE_PUB_KEY *pBsafePubKey;
if ((pPublic->aiKeyAlg != CALG_RSA_KEYX) &&
(pPublic->aiKeyAlg != CALG_RSA_SIGN))
{
SetLastError((DWORD) NTE_BAD_DATA);
return NTF_FAILED;
}
if ((pTmpKey = MakeNewKey(pPublic->aiKeyAlg,
0,
sizeof(BSAFE_PUB_KEY) +
pImpPubKey->bitlen/8 + 2*sizeof(DWORD),
hUID,
0))==NULL)
{
return NTF_FAILED;
}
pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue;
pBsafePubKey->magic = pImpPubKey->magic;
pBsafePubKey->keylen = pImpPubKey->bitlen / 8 + 2 * sizeof(DWORD);
pBsafePubKey->bitlen = pImpPubKey->bitlen;
pBsafePubKey->datalen = pImpPubKey->bitlen / 8 - 1;
pBsafePubKey->pubexp = pImpPubKey->pubexp;
memset((BYTE *) pBsafePubKey + sizeof(BSAFE_PUB_KEY),
'\0', pImpPubKey->bitlen / 8 + 2 * sizeof(DWORD));
memcpy((BYTE *) pBsafePubKey + sizeof(BSAFE_PUB_KEY),
(BYTE *) pPublic + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
pImpPubKey->bitlen/8);
if (NTLMakeItem(phKey,
(BYTE) (pPublic->aiKeyAlg == CALG_RSA_KEYX ?
EXCHPUBKEY_HANDLE : SIGPUBKEY_HANDLE),
(void *)pTmpKey) == NTF_FAILED)
{
FreeNewKey(pTmpKey);
return NTF_FAILED;
}
break;
}
case PRIVATEKEYBLOB:
{
BLOBHEADER *pPublic = (BLOBHEADER *) pbData;
PBYTE pbData2 = NULL;
DWORD cb;
size_t *pcbPub;
BYTE **ppbPub;
size_t *pcbPrv;
BYTE **ppbPrv;
BOOL fExch;
cb = dwDataLen - sizeof(BLOBHEADER);
if (NULL == (pbData2 = _nt_malloc(cb)))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
CopyMemory(pbData2, pbData + sizeof(BLOBHEADER), cb);
if (hPubKey)
{
if (!CPDecrypt(hUID, hPubKey, 0, TRUE, 0, pbData2, &cb))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
return NTF_FAILED;
}
}
if (pPublic->aiKeyAlg == CALG_RSA_KEYX)
{
pcbPub = &pTmpUser->ExchPubLen;
ppbPub = &pTmpUser->pExchPubKey;
pcbPrv = &pTmpUser->ExchPrivLen;
ppbPrv = &pTmpUser->pExchPrivKey;
fExch = TRUE;
}
else if (pPublic->aiKeyAlg == CALG_RSA_SIGN)
{
pcbPub = &pTmpUser->SigPubLen;
ppbPub = &pTmpUser->pSigPubKey;
pcbPrv = &pTmpUser->SigPrivLen;
ppbPrv = &pTmpUser->pSigPrivKey;
fExch = FALSE;
}
else
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
SetLastError((DWORD) NTE_BAD_DATA);
return NTF_FAILED;
}
if (*ppbPub)
{
ASSERT(*pcbPub);
ASSERT(*pcbPrv);
ASSERT(*ppbPrv);
memnuke(*ppbPub, *pcbPub);
_nt_free (*ppbPub, *pcbPub);
*ppbPub = NULL;
memnuke(*ppbPrv, *pcbPrv);
_nt_free (*ppbPrv, *pcbPrv);
*ppbPrv = NULL;
}
if (!PreparePrivateKeyForImport(pbData2, cb, NULL, pcbPrv, NULL, pcbPub))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
SetLastError((DWORD) NTE_BAD_DATA);
return NTF_FAILED;
}
if (NULL == (*ppbPub = _nt_malloc(*pcbPub)))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
if (NULL == (*ppbPrv = _nt_malloc(*pcbPrv)))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
if (!PreparePrivateKeyForImport(pbData2, cb, (LPBSAFE_PRV_KEY)*ppbPrv,
pcbPrv, (LPBSAFE_PUB_KEY)*ppbPub, pcbPub))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
SetLastError((DWORD) NTE_BAD_DATA);
return NTF_FAILED;
}
// write the new keys to the user storage file
if (SaveUserKeys (pTmpUser) == NTF_FAILED)
{
// ## NOTE: keys are changed, but not persistent
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
return NTF_FAILED; // error already set
}
if (!RemovePublicKeyExportability(pTmpUser, fExch))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
return NTF_FAILED;
}
if (dwFlags & CRYPT_EXPORTABLE)
{
if (!MakePublicKeyExportable(pTmpUser, fExch))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
return NTF_FAILED;
}
}
if (NTF_FAILED == CPGetUserKey(
hUID,
(fExch ? AT_KEYEXCHANGE : AT_SIGNATURE),
phKey))
{
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
return NTF_FAILED;
}
_nt_free(pbData2, dwDataLen - sizeof(BLOBHEADER));
break;
}
case SIMPLEBLOB:
{
NTSimpleBlob *ThisSB = (NTSimpleBlob *) (pbData +
sizeof(BLOBHEADER));
if (ThisSB->aiEncAlg != CALG_RSA_KEYX)
{
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
}
pBsafePrvKey = (BSAFE_PRV_KEY *) pTmpUser->pExchPrivKey;
if(NULL == pBsafePrvKey)
{
SetLastError((DWORD)NTE_NO_KEY);
return(NTF_FAILED);
}
KeyBufLen = CRYPT_BLKLEN;
#ifndef STT
if (!PKCS2Decrypt(pBsafePrvKey,
(char *) pbData +
sizeof(BLOBHEADER) + sizeof(NTSimpleBlob),
KeyBuf,
&KeyBufLen))
{
return NTF_FAILED;
}
if ((pTmpKey = MakeNewKey(ThisStdHeader->aiKeyAlg,
0,
KeyBufLen,
hUID,
KeyBuf)) == NULL)
{
return NTF_FAILED;
}
if (NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey) == NTF_FAILED)
{
_nt_free(pTmpKey->pKeyValue, pTmpKey->cbKeyLen);
_nt_free (pTmpKey, sizeof(NTAGKeyList));
return NTF_FAILED; // error already set
}
// scrub the output buffer
memnuke(KeyBuf, CRYPT_BLKLEN);
#else //STT
if (!FOADecrypt(pBsafePrvKey,
ThisStdHeader->aiKeyAlg,
hUID,
(char *) pbData +
sizeof(BLOBHEADER) + sizeof(NTSimpleBlob),
phKey))
{
return NTF_FAILED;
}
#endif //STT
break;
}
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
if (dwFlags & CRYPT_USER_PROTECTED)
{
if (CryptUserProtectKey(pTmpUser->hPrivuid, *phKey) == CPPAPI_FAILED)
{
return NTF_FAILED;
}
}
return NTF_SUCCEED;
}
/*
- 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:
*/
BOOL CPInflateKey(IN HCRYPTPROV hUID,
IN HCRYPTKEY hKey,
IN DWORD dwFlags)
{
PNTAGKeyList pTmpKey;
BYTE RealKey[TOTAL_KEY_SIZE];
if (dwFlags != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if ((pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey, hUID, KEY_HANDLE))
== NULL)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
if (GetLastError() == NTE_FAIL)
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
// if space for the key table has been allocated previously
// then free it
if (pTmpKey->pData != NULL)
{
ASSERT(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:
if ((pTmpKey->pData = (BYTE *)_nt_malloc(RC2_TABLESIZE)) == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
memcpy(RealKey, pTmpKey->pKeyValue, RC2_KEYSIZE);
memcpy(RealKey+RC2_KEYSIZE, pTmpKey->Salt,
TOTAL_KEY_SIZE-RC2_KEYSIZE);
pTmpKey->cbDataLen = RC2_TABLESIZE;
RC2Key ((WORD *)pTmpKey->pData, RealKey, TOTAL_KEY_SIZE);
memnuke(RealKey, TOTAL_KEY_SIZE);
break;
#endif
#ifdef CSP_USE_RC4
case CALG_RC4:
if ((pTmpKey->pData = (BYTE *)_nt_malloc(sizeof(RC4_KEYSTRUCT)))
== NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
memcpy(RealKey, pTmpKey->pKeyValue, RC4_KEYSIZE);
memcpy(RealKey+RC4_KEYSIZE, pTmpKey->Salt,
TOTAL_KEY_SIZE-RC4_KEYSIZE);
pTmpKey->cbDataLen = sizeof(RC4_KEYSTRUCT);
rc4_key((struct RC4_KEYSTRUCT *)pTmpKey->pData, TOTAL_KEY_SIZE,
RealKey);
memnuke(RealKey, TOTAL_KEY_SIZE);
break;
#endif
#ifdef CSP_USE_DES
case CALG_DES:
if ((pTmpKey->pData = (BYTE *)_nt_malloc(DES_TABLESIZE)) == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NTF_FAILED;
}
pTmpKey->cbDataLen = DES_TABLESIZE;
deskey((DESTable *)pTmpKey->pData, pTmpKey->pKeyValue);
break;
#endif
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
return NTF_SUCCEED;
}
/*
- 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 CPDestroyKey(IN HCRYPTPROV hUID,
IN HCRYPTKEY hKey)
{
PNTAGKeyList pTmpKey;
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if ((pTmpKey = (PNTAGKeyList) NTLValidate((HNTAG)hKey,
hUID, SIGPUBKEY_HANDLE)) == NULL &&
(pTmpKey = (PNTAGKeyList) NTLValidate((HNTAG)hKey,
hUID, EXCHPUBKEY_HANDLE)) == NULL &&
(pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, KEY_HANDLE)) == NULL)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
if (GetLastError() == NTE_FAIL) {
SetLastError((DWORD) NTE_BAD_KEY);
}
return NTF_FAILED;
}
// 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->pData) {
ASSERT(pTmpKey->cbDataLen);
memnuke(pTmpKey->pData, pTmpKey->cbDataLen);
_nt_free (pTmpKey->pData, pTmpKey->cbDataLen);
}
_nt_free (pTmpKey, sizeof(NTAGKeyList));
return NTF_SUCCEED;
}
/*
- 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 CPGetUserKey(IN HCRYPTPROV hUID,
IN DWORD dwWhichKey,
OUT HCRYPTKEY *phKey)
{
PNTAGUserList pUser;
PNTAGKeyList pTmpKey;
DWORD localWhichKey;
// check the user identification
if ((pUser = (PNTAGUserList) NTLCheckList(hUID, USER_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
switch (dwWhichKey)
{
case AT_KEYEXCHANGE:
localWhichKey = EXCHPUBKEY;
break;
case AT_SIGNATURE:
localWhichKey = SIGPUBKEY;
break;
default:
localWhichKey = dwWhichKey;
break;
}
switch(localWhichKey)
{
case SIGPUBKEY:
if (pUser->SigPubLen == 0)
{
SetLastError((DWORD) NTE_NO_KEY);
return NTF_FAILED;
}
if ((pTmpKey = MakeNewKey(CALG_RSA_SIGN,
CRYPT_EXPORTABLE,
pUser->SigPubLen,
hUID,
pUser->pSigPubKey)) == NULL)
{
return NTF_FAILED; // error already set
}
break;
case EXCHPUBKEY:
if (pUser->ExchPubLen == 0)
{
SetLastError((DWORD) NTE_NO_KEY);
return NTF_FAILED;
}
if ((pTmpKey = MakeNewKey(CALG_RSA_KEYX,
CRYPT_EXPORTABLE,
pUser->ExchPubLen,
hUID,
pUser->pExchPubKey)) == NULL)
{
return NTF_FAILED; // error already set
}
break;
default:
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
if (NTLMakeItem(phKey,
(BYTE) ((localWhichKey == SIGPUBKEY) ?
SIGPUBKEY_HANDLE :
EXCHPUBKEY_HANDLE),
(void *)pTmpKey) == NTF_FAILED)
return NTF_FAILED; // error already set
return NTF_SUCCEED;
}
/*
- 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 CPSetKeyParam(IN HCRYPTPROV hUID,
IN HCRYPTKEY hKey,
IN DWORD dwParam,
IN BYTE *pbData,
IN DWORD dwFlags)
{
PNTAGKeyList pTmpKey;
if (dwFlags != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if ((pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, KEY_HANDLE)) == NULL &&
(pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, SIGPUBKEY_HANDLE)) == NULL &&
(pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, EXCHPUBKEY_HANDLE)) == NULL)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
if (GetLastError() == NTE_FAIL)
{
SetLastError((DWORD) NTE_BAD_KEY);
}
return NTF_FAILED;
}
switch (dwParam)
{
case KP_IV:
memcpy(pTmpKey->IV, pbData, RC2_BLOCKLEN);
break;
case KP_SALT:
memcpy(pTmpKey->Salt, pbData, SALT_LENGTH);
if (NTAG_FAILED(CPInflateKey(hUID, hKey, 0)))
{
return NTF_FAILED;
}
break;
case KP_PADDING:
if (*((DWORD *) pbData) != PKCS5_PADDING)
{
SetLastError((DWORD) NTE_BAD_DATA);
return NTF_FAILED;
}
break;
case KP_MODE:
if ((HNTAG_TO_HTYPE(hKey) != KEY_HANDLE) &&
pTmpKey->Algid != CALG_RC2)
{
SetLastError((DWORD) NTE_BAD_KEY);
return NTF_FAILED;
}
if (*pbData != CRYPT_MODE_CBC &&
*pbData != CRYPT_MODE_ECB &&
*pbData != CRYPT_MODE_CFB)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
pTmpKey->Mode = *((DWORD *) pbData);
break;
case KP_MODE_BITS:
pTmpKey->ModeBits = *((DWORD *) pbData);
break;
case KP_PERMISSIONS:
if (*pbData != CRYPT_ENCRYPT &&
*pbData != CRYPT_DECRYPT &&
*pbData != CRYPT_EXPORT &&
*pbData != CRYPT_READ &&
*pbData != CRYPT_WRITE &&
*pbData != CRYPT_MAC)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
pTmpKey->Permissions = *((DWORD *) pbData);
break;
#ifdef STT
case KP_INFO:
pTmpKey->cbInfo = strlen(pbData);
memcpy(pTmpKey->rgbInfo, pbData, pTmpKey->cbInfo);
break;
#endif //STT
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
return NTF_SUCCEED;
}
/*
- 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 CPGetKeyParam(IN HCRYPTPROV hUID,
IN HCRYPTKEY hKey,
IN DWORD dwParam,
IN BYTE *pbData,
IN DWORD *pwDataLen,
IN DWORD dwFlags)
{
PNTAGKeyList pTmpKey;
BSAFE_PUB_KEY *pBsafePubKey;
if (dwFlags != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if ((pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, KEY_HANDLE)) == NULL &&
(pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, SIGPUBKEY_HANDLE)) == NULL &&
(pTmpKey = (PNTAGKeyList)NTLValidate((HNTAG)hKey,
hUID, EXCHPUBKEY_HANDLE)) == NULL)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
if (GetLastError() == NTE_FAIL)
{
SetLastError((DWORD) NTE_BAD_KEY);
}
return NTF_FAILED;
}
if (pwDataLen == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NTF_FAILED;
}
switch (dwParam)
{
case KP_IV:
if (pbData == NULL || *pwDataLen < RC2_BLOCKLEN)
{
*pwDataLen = RC2_BLOCKLEN;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
memcpy(pbData, pTmpKey->IV, RC2_BLOCKLEN);
*pwDataLen = RC2_BLOCKLEN;
break;
case KP_SALT:
if (pbData == NULL || (*pwDataLen < SALT_LENGTH))
{
*pwDataLen = SALT_LENGTH;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
memcpy(pbData, pTmpKey->Salt, SALT_LENGTH);
*pwDataLen = SALT_LENGTH;
break;
case KP_PADDING:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*((DWORD *) pbData) = PKCS5_PADDING;
*pwDataLen = sizeof(DWORD);
break;
case KP_MODE:
*((DWORD *) pbData) = pTmpKey->Mode;
*pwDataLen = sizeof(DWORD);
break;
case KP_MODE_BITS:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*((DWORD *) pbData) = pTmpKey->ModeBits;
*pwDataLen = sizeof(DWORD);
break;
case KP_PERMISSIONS:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*((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)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*((ALG_ID *) pbData) = pTmpKey->Algid;
*pwDataLen = sizeof(ALG_ID);
break;
case KP_BLOCKLEN:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
if (pTmpKey->Algid == CALG_RC2)
{
*((DWORD *) pbData) = RC2_BLOCKLEN * 8;
*pwDataLen = sizeof(DWORD);
}
else if ((HNTAG_TO_HTYPE(hKey) == SIGPUBKEY_HANDLE) ||
(HNTAG_TO_HTYPE(hKey) == EXCHPUBKEY_HANDLE))
{
pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue;
if (pBsafePubKey == NULL)
{
SetLastError((DWORD) NTE_NO_KEY);
return NTF_FAILED;
}
*((DWORD *) pbData) = pBsafePubKey->bitlen;
*pwDataLen = sizeof(DWORD);
}
else
{
*((DWORD *) pbData) = 0;
*pwDataLen = sizeof(DWORD);
}
break;
#ifdef STT
case KP_INFO:
*pwDataLen = pTmpKey->cbInfo;
if(NULL == pbData)
{
return(NTF_SUCCEED);
}
memcpy(pbData, pTmpKey->rgbInfo, *pwDataLen);
break;
#endif //STT
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
return NTF_SUCCEED;
}
/*
- 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 CPSetProvParam(IN HCRYPTPROV hUID,
IN DWORD dwParam,
IN BYTE *pbData,
IN DWORD dwFlags)
{
PNTAGUserList pTmpUser;
long lsyserr;
if (NULL == (pTmpUser = (PNTAGUserList)NTLCheckList (hUID, USER_HANDLE)))
{
SetLastError((DWORD)NTE_BAD_UID);
return NTF_FAILED;
}
switch (dwParam)
{
case PP_KEYSET_SEC_DESCR:
if (!(dwFlags & OWNER_SECURITY_INFORMATION) &&
!(dwFlags & GROUP_SECURITY_INFORMATION) &&
!(dwFlags & DACL_SECURITY_INFORMATION) &&
!(dwFlags & SACL_SECURITY_INFORMATION))
{
SetLastError((DWORD)NTE_BAD_FLAGS);
return NTF_FAILED;
}
// set the security descriptor for the hKey of the keyset
if (lsyserr = RegSetKeySecurity(pTmpUser->hKeys,
(SECURITY_INFORMATION)dwFlags,
(PSECURITY_DESCRIPTOR)pbData))
{
if (ERROR_NOT_SUPPORTED == lsyserr)
{
SetLastError((DWORD)ERROR_NOT_SUPPORTED);
return NTF_FAILED;
}
else
{
SetLastError((DWORD)NTE_FAIL);
return NTF_FAILED;
}
}
break;
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
return NTF_SUCCEED;
}
/*
- 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 CPGetProvParam(IN HCRYPTPROV hUID,
IN DWORD dwParam,
IN BYTE *pbData,
IN DWORD *pwDataLen,
IN DWORD dwFlags)
{
PNTAGUserList pTmpUser;
HKEY hKey;
long lsyserr;
CHAR szClass[50];
DWORD cchClass;
DWORD cSubKeys;
DWORD cchMaxSubkey;
DWORD cchMaxClass;
DWORD cValues;
DWORD cchMaxValueName;
DWORD cbMaxValueData;
DWORD cbSecurityDesriptor;
FILETIME ftLastWriteTime;
if ((pTmpUser = (PNTAGUserList) NTLCheckList (hUID, USER_HANDLE)) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if (pwDataLen == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NTF_FAILED;
}
switch (dwParam)
{
case PP_ENUMALGS:
if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT)) != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
if (dwFlags & CRYPT_FIRST)
{
pTmpUser->dwEnumalgs = 0;
}
if (ENUMALGS[pTmpUser->dwEnumalgs].aiAlgid == 0)
{
SetLastError(ERROR_NO_MORE_ITEMS);
return NTF_FAILED;
}
if (pbData == NULL || *pwDataLen < sizeof(ENUMALGS[1]))
{
*pwDataLen = sizeof(ENUMALGS[1]);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
memcpy(pbData, &ENUMALGS[pTmpUser->dwEnumalgs],
sizeof(ENUMALGS[1]));
*pwDataLen = sizeof(ENUMALGS[1]);
pTmpUser->dwEnumalgs++;
break;
case PP_ENUMCONTAINERS:
{
BOOL fMachnieKeySet = pTmpUser->Rights & CRYPT_MACHINE_KEYSET;
if ((dwFlags & ~(CRYPT_FIRST | CRYPT_NEXT)) != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
#ifdef _CMRNTAG
if ((lsyserr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
NTAG_REG_KEY_LOC,
0,
KEY_READ,
&hKey)) != ERROR_SUCCESS)
#else
if ((lsyserr = RegOpenKeyEx(fMachnieKeySet ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
fMachnieKeySet ? NTAG_MACH_REG_KEY_LOC : NTAG_REG_KEY_LOC,
0,
KEY_READ,
&hKey)) != ERROR_SUCCESS)
#endif // _CMRNTAG
{
SetLastError(lsyserr);
return NTF_FAILED;
}
if (dwFlags & CRYPT_FIRST)
{
pTmpUser->dwiSubKey = 0;
if ((lsyserr = RegQueryInfoKey(hKey,
(CHAR *) &szClass,
&cchClass,
NULL,
&cSubKeys,
&cchMaxSubkey,
&cchMaxClass,
&cValues,
&cchMaxValueName,
&cbMaxValueData,
&cbSecurityDesriptor,
&ftLastWriteTime
)) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
SetLastError(lsyserr);
return NTF_FAILED;
}
pTmpUser->dwMaxSubKey = cchMaxSubkey + 1;
}
if (pbData == NULL || *pwDataLen < pTmpUser->dwMaxSubKey)
{
*pwDataLen = pTmpUser->dwMaxSubKey;
if (pbData == NULL)
{
RegCloseKey(hKey);
return NTF_SUCCEED;
}
RegCloseKey(hKey);
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
if ((lsyserr = RegEnumKey(hKey,
pTmpUser->dwiSubKey,
pbData,
*pwDataLen)) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
SetLastError(lsyserr);
return NTF_FAILED;
}
RegCloseKey(hKey);
pTmpUser->dwiSubKey++;
}
break;
case PP_IMPTYPE:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
RegCloseKey(hKey);
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*pwDataLen = sizeof(DWORD);
*((DWORD *) pbData) = CRYPT_IMPL_SOFTWARE;
break;
case PP_NAME:
if (pbData == NULL || *pwDataLen < sizeof(MS_DEF_PROV))
{
*pwDataLen = sizeof(MS_DEF_PROV);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*pwDataLen = sizeof(MS_DEF_PROV);
memcpy(pbData, MS_DEF_PROV, sizeof(MS_DEF_PROV));
break;
case PP_VERSION:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*pwDataLen = sizeof(DWORD);
*((DWORD *) pbData) = 0x100;
break;
case PP_CONTAINER:
if (pbData == NULL || *pwDataLen < pTmpUser->dwUserNameLen)
{
*pwDataLen = pTmpUser->dwUserNameLen;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*pwDataLen = pTmpUser->dwUserNameLen;
strcpy(pbData, pTmpUser->szUserName);
break;
case PP_KEYSET_SEC_DESCR:
if (!(dwFlags & OWNER_SECURITY_INFORMATION) &&
!(dwFlags & GROUP_SECURITY_INFORMATION) &&
!(dwFlags & DACL_SECURITY_INFORMATION) &&
!(dwFlags & SACL_SECURITY_INFORMATION))
{
SetLastError((DWORD)NTE_BAD_FLAGS);
return NTF_FAILED;
}
// get the security descriptor for the hKey of the keyset
if (NULL == pbData)
{
cbSecurityDesriptor = 0;
if (ERROR_INSUFFICIENT_BUFFER !=
(lsyserr = RegGetKeySecurity(pTmpUser->hKeys,
(SECURITY_INFORMATION)dwFlags,
&cbSecurityDesriptor,
&cbSecurityDesriptor)))
{
if (ERROR_NOT_SUPPORTED == lsyserr)
{
SetLastError((DWORD)ERROR_NOT_SUPPORTED);
return NTF_FAILED;
}
else
{
SetLastError((DWORD)NTE_FAIL);
return NTF_FAILED;
}
}
*pwDataLen = cbSecurityDesriptor;
}
else
{
if (lsyserr = RegGetKeySecurity(pTmpUser->hKeys,
(SECURITY_INFORMATION)dwFlags,
(PSECURITY_DESCRIPTOR)pbData,
pwDataLen))
{
if (ERROR_INSUFFICIENT_BUFFER == lsyserr)
{
SetLastError((DWORD)ERROR_MORE_DATA);
return NTF_FAILED;
}
else if (ERROR_NOT_SUPPORTED == lsyserr)
{
SetLastError((DWORD)ERROR_NOT_SUPPORTED);
return NTF_FAILED;
}
else
{
SetLastError((DWORD)NTE_FAIL);
return NTF_FAILED;
}
}
}
break;
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
return NTF_SUCCEED;
}
/*
- 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 CPSetHashParam(IN HCRYPTPROV hUID,
IN HCRYPTHASH hHash,
IN DWORD dwParam,
IN BYTE *pbData,
IN DWORD dwFlags)
{
PNTAGHashList pTmpHash;
PNTAGKeyList pTmpKey;
MD4_object *pMD4Hash;
MD5_object *pMD5Hash;
A_SHA_CTX *pSHAHash;
MACstate *pMAC;
if (dwFlags != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if ((pTmpHash = (PNTAGHashList) NTLValidate(hHash, hUID,
HASH_HANDLE)) == NULL)
{
if (GetLastError() == NTE_FAIL)
SetLastError((DWORD) NTE_BAD_HASH);
return NTF_FAILED;
}
switch (dwParam)
{
case HP_HASHVAL:
switch (pTmpHash->Algid)
{
#ifdef CSP_USE_MD4
case CALG_MD4:
pMD4Hash = (MD4_object *) pTmpHash->pHashData;
if (pMD4Hash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
memcpy (&pMD4Hash->MD, pbData, MD4DIGESTLEN);
break;
#endif
#ifdef CSP_USE_MD5
case CALG_MD5:
pMD5Hash = (MD5_object *) pTmpHash->pHashData;
if (pMD5Hash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
memcpy (pMD5Hash->digest, pbData, MD5DIGESTLEN);
break;
#endif
#ifdef CSP_USE_SHA
case CALG_SHA:
pSHAHash = (A_SHA_CTX *) pTmpHash->pHashData;
if (pSHAHash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
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;
if ((pTmpKey = (PNTAGKeyList) NTLValidate(pMAC->hKey,
hUID,
KEY_HANDLE)) == NULL)
{
if (GetLastError() == NTE_FAIL)
{
SetLastError((DWORD) NTE_BAD_KEY);
}
return NTF_FAILED;
}
if (pMAC->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
memcpy(pTmpKey->FeedBack, pbData, CRYPT_BLKLEN);
break;
#endif
default:
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
}
break;
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
if (dwParam == HP_HASHVAL)
pTmpHash->HashFlags |= HF_VALUE_SET;
return NTF_SUCCEED;
}
/*
- 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 CPGetHashParam(IN HCRYPTPROV hUID,
IN HCRYPTHASH hHash,
IN DWORD dwParam,
IN BYTE *pbData,
IN DWORD *pwDataLen,
IN DWORD dwFlags)
{
PNTAGHashList pTmpHash;
MD2_object *pMD2Hash;
MD4_object *pMD4Hash;
MD5_object *pMD5Hash;
A_SHA_CTX *pSHAHash;
MACstate *pMAC;
BOOL f;
BYTE MACbuf[2*CRYPT_BLKLEN];
PNTAGKeyList pTmpKey;
if (dwFlags != 0)
{
SetLastError((DWORD) NTE_BAD_FLAGS);
return NTF_FAILED;
}
// check the user identification
if (NTLCheckList ((HNTAG)hUID, USER_HANDLE) == NULL)
{
SetLastError((DWORD) NTE_BAD_UID);
return NTF_FAILED;
}
if (pwDataLen == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NTF_FAILED;
}
if ((pTmpHash = (PNTAGHashList) NTLValidate(hHash, hUID,
HASH_HANDLE)) == NULL)
{
if (GetLastError() == NTE_FAIL)
SetLastError((DWORD) NTE_BAD_HASH);
return NTF_FAILED;
}
switch (dwParam)
{
case HP_ALGID:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
*((DWORD *) pbData) = pTmpHash->Algid;
*pwDataLen = sizeof(DWORD);
break;
case HP_HASHSIZE:
if (pbData == NULL || *pwDataLen < sizeof(DWORD))
{
*pwDataLen = sizeof(DWORD);
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
switch (pTmpHash->Algid)
{
#ifdef CSP_USE_MD2
case CALG_MD2:
*((DWORD *) pbData) = MD2DIGESTLEN;
break;
#endif
#ifdef CSP_USE_MD4
case CALG_MD4:
*((DWORD *) pbData) = MD4DIGESTLEN;
break;
#endif
#ifdef CSP_USE_MD5
case CALG_MD5:
*((DWORD *) pbData) = MD5DIGESTLEN;
break;
#endif
#ifdef CSP_USE_SHA
case CALG_SHA:
*((DWORD *) pbData) = A_SHA_DIGEST_LEN;
break;
#endif
#ifdef CSP_USE_MAC
case CALG_MAC:
*((DWORD *) pbData) = CRYPT_BLKLEN;
break;
#endif
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5:
*((DWORD *) pbData) = SSL3_SHAMD5_LEN;
break;
#endif
default:
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
}
*pwDataLen = sizeof(DWORD);
break;
case HP_HASHVAL:
switch (pTmpHash->Algid)
{
#ifdef CSP_USE_MD2
case CALG_MD2:
// make sure there's enough room.
if (pbData == NULL || *pwDataLen < MD2DIGESTLEN)
{
*pwDataLen = MD2DIGESTLEN;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
pMD2Hash = (MD2_object *) pTmpHash->pHashData;
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
if (pMD2Hash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
// set the finish flag on the hash and
// process what's left in the buffer.
pMD2Hash->FinishFlag = TRUE;
// Finish offthe hash
MD2Final(&pMD2Hash->MD);
}
*pwDataLen = MD2DIGESTLEN;
memcpy (pbData, pMD2Hash->MD.state, MD5DIGESTLEN);
break;
#endif
#ifdef CSP_USE_MD4
case CALG_MD4:
// make sure there's enough room.
if (pbData == NULL || *pwDataLen < MD4DIGESTLEN)
{
*pwDataLen = MD4DIGESTLEN;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
pMD4Hash = (MD4_object *) pTmpHash->pHashData;
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
if (pMD4Hash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
// set the finish flag on the hash and
// process what's left in the buffer.
pMD4Hash->FinishFlag = TRUE;
f = MDupdate(&pMD4Hash->MD, pMD4Hash->Buf,
MD4BYTESTOBITS(pMD4Hash->BufLen));
if (f != MD4_SUCCESS)
{
SetLastError((DWORD) NTE_FAIL);
return NTF_FAILED;
}
}
*pwDataLen = MD4DIGESTLEN;
memcpy(pbData, &pMD4Hash->MD, *pwDataLen);
break;
#endif
#ifdef CSP_USE_MD5
case CALG_MD5:
// make sure there's enough room.
if (pbData == NULL || *pwDataLen < MD5DIGESTLEN)
{
*pwDataLen = MD5DIGESTLEN;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
pMD5Hash = (MD5_object *) pTmpHash->pHashData;
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
if (pMD5Hash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
// set the finish flag on the hash and
// process what's left in the buffer.
pMD5Hash->FinishFlag = TRUE;
// Finish offthe hash
MD5Final(pMD5Hash);
}
*pwDataLen = MD5DIGESTLEN;
memcpy (pbData, pMD5Hash->digest, MD5DIGESTLEN);
break;
#endif
#ifdef CSP_USE_SHA
case CALG_SHA:
// make sure there's enough room.
if (pbData == NULL || *pwDataLen < A_SHA_DIGEST_LEN)
{
*pwDataLen = A_SHA_DIGEST_LEN;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
pSHAHash = (A_SHA_CTX *) pTmpHash->pHashData;
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
if (pSHAHash->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
// 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);
}
*pwDataLen = A_SHA_DIGEST_LEN;
memcpy (pbData, pSHAHash->HashVal, A_SHA_DIGEST_LEN);
break;
#endif
#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;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
// Hash value must have already been set.
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
*pwDataLen = SSL3_SHAMD5_LEN;
memcpy (pbData, pTmpHash->pHashData, SSL3_SHAMD5_LEN);
break;
#endif
#ifdef CSP_USE_MAC
case CALG_MAC:
pMAC = (MACstate *)pTmpHash->pHashData;
if ((pTmpKey = (PNTAGKeyList) NTLValidate(pMAC->hKey,
hUID,
KEY_HANDLE)) == NULL)
{
if (GetLastError() == NTE_FAIL)
{
SetLastError((DWORD) NTE_BAD_KEY);
}
return NTF_FAILED;
}
// make sure there is enough room.
if (pbData == NULL || (*pwDataLen < CRYPT_BLKLEN))
{
*pwDataLen = CRYPT_BLKLEN;
if (pbData == NULL)
{
return NTF_SUCCEED;
}
SetLastError(ERROR_MORE_DATA);
return NTF_FAILED;
}
if (pMAC->FinishFlag == TRUE)
{
SetLastError((DWORD) NTE_BAD_HASH_STATE);
return NTF_FAILED;
}
// 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*CRYPT_BLKLEN);
memcpy(MACbuf, pMAC->Buffer, pMAC->dwBufLen);
switch (pTmpKey->Algid)
{
case CALG_RC2:
if (BlockEncrypt(RC2, pTmpKey, RC2_BLOCKLEN, TRUE,
MACbuf, &pMAC->dwBufLen,
2*CRYPT_BLKLEN) == NTF_FAILED)
{
return NTF_FAILED;
}
break;
case CALG_DES:
if (BlockEncrypt(des, pTmpKey, DES_BLOCKLEN, TRUE,
MACbuf, &pMAC->dwBufLen,
2*CRYPT_BLKLEN) == NTF_FAILED)
{
return NTF_FAILED;
}
}
}
*pwDataLen = CRYPT_BLKLEN;
memcpy(pbData, pTmpKey->FeedBack, CRYPT_BLKLEN);
break;
#endif
default:
SetLastError((DWORD) NTE_BAD_ALGID);
return NTF_FAILED;
}
break;
default:
SetLastError((DWORD) NTE_BAD_TYPE);
return NTF_FAILED;
break;
}
return NTF_SUCCEED;
}
#ifdef STT
//Optimal Asymmtric ( Bellare-Rogoway )
BOOL FOAEncrypt(IN HCRYPTPROV hUID, BSAFE_PUB_KEY *pBSPubKey,
PNTAGKeyList pTmpKey,
BYTE *pbOut)
{
BYTE *pbInput = NULL;
BYTE *pbOutput = NULL;
DWORD dwLen;
BOOL fSucc = FALSE;
DWORD dwLastErr = NTE_FAIL;
// Copy key to internal buffer (disguised as pBlobHeader)
// -- put it after the pBlobHeader fields.
if((pbInput = (BYTE *)_nt_malloc(pBSPubKey->keylen)) == NULL)
{
dwLastErr = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
memset(pbInput, 0, pBSPubKey->keylen);
memcpy(pbInput, &pTmpKey->cbKeyLen, sizeof(DWORD));
dwLen = sizeof(DWORD);
memcpy(pbInput + dwLen,
pTmpKey->pKeyValue, pTmpKey->cbKeyLen);
dwLen += pTmpKey->cbKeyLen;
if(pTmpKey->Algid == CALG_DES)
{
// copy the other data into the internal buffer
memcpy(pbInput + dwLen, &pTmpKey->cbInfo, sizeof(DWORD));
dwLen += sizeof(DWORD);
memcpy(pbInput + dwLen, pTmpKey->rgbInfo, pTmpKey->cbInfo);
dwLen += pTmpKey->cbInfo;
}
// put in Bellare-Rogoway formatting
if (FALSE == ApplyPadding(hUID, pbInput, pBSPubKey->datalen, dwLen))
goto Ret;
if((pbOutput = (BYTE *)_nt_malloc(pBSPubKey->keylen)) == NULL)
{
dwLastErr = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
memset (pbOutput, 0, pBSPubKey->keylen);
// RSA encrypt this
if (FALSE == BSafeEncPublic(pBSPubKey, pbInput, pbOutput))
goto Ret;
memset (pbOut, 0, pBSPubKey->keylen-2*sizeof(DWORD));
memcpy(pbOut, pbOutput, pBSPubKey->keylen-2*sizeof(DWORD));
fSucc = TRUE;
Ret:
if(!fSucc)
SetLastError(dwLastErr);
_nt_free(pbInput, pBSPubKey->keylen);
_nt_free(pbOutput, pBSPubKey->keylen);
return fSucc;
}
//Optimal Asymmtric ( Bellare-Rogoway )
BOOL FOADecrypt(BSAFE_PRV_KEY *pKey,
ALG_ID Algid,
HCRYPTPROV hUID,
BYTE *pbBlob,
HCRYPTKEY *phKey)
{
BYTE* pbOutput = NULL;
BYTE* pbInput = NULL;
BYTE* pbKey = NULL;
DWORD cbKey;
DWORD dwLen;
DWORD cbKeyTmp;
NTAGKeyList *pTmpKey = NULL;
BOOL fSucc = FALSE;
DWORD dwErr = NTE_FAIL;
int i;
if ((pbOutput = (BYTE *)_nt_malloc(pKey->keylen)) == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
if ((pbInput = (BYTE *)_nt_malloc(pKey->keylen)) == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
memset(pbInput, 0, pKey->keylen);
memset(pbOutput, 0, pKey->keylen);
memcpy(pbInput, pbBlob, pKey->keylen-2*sizeof(DWORD));
if (FALSE == BSafeDecPrivate(pKey,
pbInput,
pbOutput))
goto Ret;
// Check Bellare-Rogoway padding
if (FALSE == CheckPadding(pbOutput, pKey->datalen))
goto Ret;
// determine the type of key being imported
switch(Algid)
{
case CALG_DES:
cbKeyTmp = DES_KEYSIZE;
break;
case CALG_RC4:
cbKeyTmp = RC4_KEYSIZE;
break;
#ifdef TEST_VERSION
case CALG_RC2:
cbKeyTmp = RC2_KEYSIZE;
break;
#endif
default:
goto Ret;
}
if ((pbKey = (BYTE *)_nt_malloc(cbKeyTmp)) == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
// get the key data out of the decrypted blob
memcpy(&cbKey, pbOutput, sizeof(DWORD));
dwLen = sizeof(DWORD);
// make sure that the key pulled out is the correct size
if (cbKeyTmp != cbKey)
goto Ret;
memcpy(pbKey, pbOutput + dwLen, cbKey);
dwLen += cbKey;
if ((pTmpKey = (PNTAGKeyList)MakeNewKey(Algid, 0, cbKey, hUID, pbKey)) == NULL)
goto Ret;
//CONSIDER: SetParam
if (CALG_DES == Algid)
{
// get the other data out of the blob
memcpy(&pTmpKey->cbInfo, pbOutput + dwLen, sizeof(DWORD));
if(pTmpKey->cbInfo > MAXCCNLEN)
goto Ret;
dwLen += sizeof(DWORD);
memcpy(pTmpKey->rgbInfo, pbOutput + dwLen, pTmpKey->cbInfo);
dwLen += pTmpKey->cbInfo;
}
// check that the rest of the bytes are 0x00
for (i=dwLen;i<(long)pKey->keylen;i++)
if (0 != pbOutput[i])
goto CCNErr;
if (NTLMakeItem(phKey, KEY_HANDLE, (void *)pTmpKey) == NTF_FAILED)
{
CCNErr:
memnuke(pTmpKey->pKeyValue, pTmpKey->cbKeyLen);
memnuke((PBYTE)pTmpKey, sizeof(NTAGKeyList));
_nt_free(pTmpKey->pKeyValue, pTmpKey->cbKeyLen);
_nt_free(pTmpKey, sizeof(NTAGKeyList));
goto Ret;
}
fSucc = TRUE;
Ret:
// scrub the output buffer
if(!fSucc)
SetLastError(dwErr);
memnuke(pbOutput, pKey->keylen);
memnuke(pbKey, cbKeyTmp);
_nt_free(pbOutput, pKey->keylen);
_nt_free(pbInput, pKey->keylen);
_nt_free(pbKey, cbKeyTmp);
return fSucc;
}
/************************************************************************/
/* ApplyPadding applies Bellare-Rogoway padding to a RSA key blob. */
/************************************************************************/
BOOL ApplyPadding ( HCRYPTPROV hUID,
BYTE* pb,
DWORD cb,
DWORD cbData
)
{
BYTE rgbKey[RC4_KEYSIZE];
RC4_KEYSTRUCT KeyStruct;
A_SHA_CTX SHACtx;
BYTE rgbDigest[A_SHA_DIGEST_LEN];
long i;
// generate a random RC4 key
cb -= RC4_KEYSIZE;
if (FALSE == GenRandom(hUID, rgbKey, RC4_KEYSIZE))
return FALSE;
// RC4 encrypt the data
rc4_key(&KeyStruct, RC4_KEYSIZE, rgbKey);
rc4(&KeyStruct, cb, pb);
// SHA the encrypted data
A_SHAInit(&SHACtx);
A_SHAUpdate(&SHACtx, pb, cb);
A_SHAFinal(&SHACtx, rgbDigest);
for (i=0;i<RC4_KEYSIZE;i++)
pb[cb + (DWORD)i] = rgbKey[i] ^ rgbDigest[i];
return TRUE;
}
/************************************************************************/
/* CheckPadding checks Bellare-Rogoway padding on a RSA key blob. */
/************************************************************************/
BOOL CheckPadding (
BYTE* pb,
DWORD cb
)
{
BYTE rgbKey[RC4_KEYSIZE];
RC4_KEYSTRUCT KeyStruct;
A_SHA_CTX SHACtx;
BYTE rgbDigest[A_SHA_DIGEST_LEN];
long i;
// generate a random RC4 key
cb -= RC4_KEYSIZE;
// SHA the encrypted data
A_SHAInit(&SHACtx);
A_SHAUpdate(&SHACtx, pb, cb);
A_SHAFinal(&SHACtx, rgbDigest);
for (i=0;i<RC4_KEYSIZE;i++)
rgbKey[i] = pb[cb + (DWORD)i] ^ rgbDigest[i];
memset(pb + cb, 0, RC4_KEYSIZE);
// RC4 decrypt the data
rc4_key(&KeyStruct, RC4_KEYSIZE, rgbKey);
rc4(&KeyStruct, cb, pb);
return TRUE;
}
#endif //STT