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