///////////////////////////////////////////////////////////////////////////// // FILE : nt_crypt.c // // DESCRIPTION : Crypto CP interfaces: // // CPEncrypt // // CPDecrypt // // AUTHOR : // // HISTORY : // // Jan 25 1995 larrys Changed from Nametag // // Jan 30 1995 larrys Cleanup code // // Feb 23 1995 larrys Changed NTag_SetLastError to SetLastError // // Apr 10 1995 larrys Added freeing of RC4 key data on final flag // // May 8 1995 larrys Changes for MAC hashing // // May 9 1995 larrys Added check for double encryption // // May 10 1995 larrys added private api calls // // Jul 13 1995 larrys Changed MAC stuff // // Aug 16 1995 larrys Removed exchange key stuff // // Oct 05 1995 larrys Fixed bugs 50 & 51 // // Nov 8 1995 larrys Fixed SUR bug 10769 // // May 15 1996 larrys Changed NTE_NO_MEMORY to ERROR_NOT_ENOUGH... // // May 3 2000 dbarlow Fix return codes // // // // Copyright (C) 1993 Microsoft Corporation All Rights Reserved // ///////////////////////////////////////////////////////////////////////////// #include "precomp.h" #include "nt_rsa.h" #include "mac.h" #include "tripldes.h" #include "swnt_pk.h" #include "protstor.h" #include "ntagum.h" #include "aes.h" #define DE_BLOCKLEN 8 // size of double encrypt block BYTE dbDEncrypt[DE_BLOCKLEN]; // First 8 bytes of last encrypt BOOL fDEncrypt = FALSE; // Flag for Double encrypt BYTE dbDDecrypt[DE_BLOCKLEN]; // First 8 bytes of last Decrypt DWORD fDDecrypt = FALSE; // Flag for Double Decrypt extern CSP_STRINGS g_Strings; extern BOOL FIsLegalKey( PNTAGUserList pTmpUser, PNTAGKeyList pKey, BOOL fRC2BigKeyOK); extern DWORD InflateKey( IN PNTAGKeyList pTmpKey); /* BlockEncrypt - Run a block cipher over a block of size *pdwDataLen. */ DWORD BlockEncrypt( void EncFun(BYTE *In, BYTE *Out, void *key, int op), PNTAGKeyList pKey, int BlockLen, BOOL Final, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD cbPartial, dwPadVal, dwDataLen; BYTE *pbBuf; dwDataLen = *pdwDataLen; // Check to see if we are encrypting something already if (pKey->InProgress == FALSE) { pKey->InProgress = TRUE; if (pKey->Mode == CRYPT_MODE_CBC || pKey->Mode == CRYPT_MODE_CFB) memcpy(pKey->FeedBack, pKey->IV, BlockLen); } // check length of the buffer and calculate the pad // (if multiple of blocklen, do a full block of pad) cbPartial = (dwDataLen % BlockLen); if (Final) { dwPadVal = BlockLen - cbPartial; if (pbData == NULL || dwBufLen < dwDataLen + dwPadVal) { // set what we need *pdwDataLen = dwDataLen + dwPadVal; dwReturn = (NULL == pbData) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; } else { // Clear encryption flag pKey->InProgress = FALSE; } } else { if (pbData == NULL) { *pdwDataLen = dwDataLen; dwReturn = ERROR_SUCCESS; goto ErrorExit; } // Non-Final make multiple of the blocklen if (cbPartial) { // set what we need *pdwDataLen = dwDataLen + cbPartial; ASSERT((*pdwDataLen % BlockLen) == 0); dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } dwPadVal = 0; } // allocate memory for a temporary buffer if ((pbBuf = (BYTE *)_nt_malloc(BlockLen)) == NULL) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } if (dwPadVal) { // Fill the pad with a value equal to the // length of the padding, so decrypt will // know the length of the original data // and as a simple integrity check. memset(pbData + dwDataLen, (int)dwPadVal, (size_t)dwPadVal); } dwDataLen += dwPadVal; *pdwDataLen = dwDataLen; ASSERT((dwDataLen % BlockLen) == 0); // pump the full blocks of data through while (dwDataLen) { ASSERT(dwDataLen >= (DWORD)BlockLen); // put the plaintext into a temporary // buffer, then encrypt the data // back into the caller's buffer memcpy(pbBuf, pbData, BlockLen); switch (pKey->Mode) { case CRYPT_MODE_CBC: CBC(EncFun, BlockLen, pbData, pbBuf, pKey->pData, ENCRYPT, pKey->FeedBack); break; case CRYPT_MODE_ECB: EncFun(pbData, pbBuf, pKey->pData, ENCRYPT); break; case CRYPT_MODE_CFB: CFB(EncFun, BlockLen, pbData, pbBuf, pKey->pData, ENCRYPT, pKey->FeedBack); break; default: _nt_free(pbBuf, BlockLen); dwReturn = (DWORD) NTE_BAD_ALGID; goto ErrorExit; } pbData += BlockLen; dwDataLen -= BlockLen; } _nt_free(pbBuf, BlockLen); dwReturn = ERROR_SUCCESS; ErrorExit: return dwReturn; } DWORD BlockDecrypt( void DecFun(BYTE *In, BYTE *Out, void *key, int op), PNTAGKeyList pKey, int BlockLen, BOOL Final, BYTE *pbData, DWORD *pdwDataLen) { DWORD dwReturn = ERROR_INTERNAL_ERROR; BYTE *pbBuf; DWORD dwDataLen, BytePos, dwPadVal, i; dwDataLen = *pdwDataLen; // Check to see if we are decrypting something already if (pKey->InProgress == FALSE) { pKey->InProgress = TRUE; if (pKey->Mode == CRYPT_MODE_CBC || pKey->Mode == CRYPT_MODE_CFB) { memcpy(pKey->FeedBack, pKey->IV, BlockLen); } } // The data length must be a multiple of the algorithm // pad size. if (dwDataLen % BlockLen) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } // allocate memory for a temporary buffer if ((pbBuf = (BYTE *)_nt_malloc(BlockLen)) == NULL) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } // pump the data through the decryption, including padding // NOTE: the total length is a multiple of BlockLen for (BytePos = 0; (BytePos + BlockLen) <= dwDataLen; BytePos += BlockLen) { // put the encrypted text into a temp buffer memcpy (pbBuf, pbData + BytePos, BlockLen); switch (pKey->Mode) { case CRYPT_MODE_CBC: CBC(DecFun, BlockLen, pbData + BytePos, pbBuf, pKey->pData, DECRYPT, pKey->FeedBack); break; case CRYPT_MODE_ECB: DecFun(pbData + BytePos, pbBuf, pKey->pData, DECRYPT); break; case CRYPT_MODE_CFB: CFB(DecFun, BlockLen, pbData + BytePos, pbBuf, pKey->pData, DECRYPT, pKey->FeedBack); break; default: _nt_free(pbBuf, BlockLen); dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } } _nt_free(pbBuf, BlockLen); // if this is the final block of data then // verify the padding and remove the pad size // from the data length. NOTE: The padding is // filled with a value equal to the length // of the padding and we are guaranteed >= 1 // byte of pad. // ## NOTE: if the pad is wrong, the user's // buffer is hosed, because // ## we've decrypted into the user's // buffer -- can we re-encrypt it? if (Final) { pKey->InProgress = FALSE; dwPadVal = (DWORD)*(pbData + dwDataLen - 1); if (dwPadVal == 0 || dwPadVal > (DWORD) BlockLen) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } // Make sure all the (rest of the) pad bytes are correct. for (i=1; iAlgid) { #ifdef CSP_USE_RC2 case CALG_RC2: dwSts = BlockEncrypt(RC2, pKey, RC2_BLOCKLEN, fFinal, pbData, pcbData, cbBuf); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif #ifdef CSP_USE_DES case CALG_DES: dwSts = BlockEncrypt(des, pKey, DES_BLOCKLEN, fFinal, pbData, pcbData, cbBuf); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif #ifdef CSP_USE_3DES case CALG_3DES_112: case CALG_3DES: dwSts = BlockEncrypt(tripledes, pKey, DES_BLOCKLEN, fFinal, pbData, pcbData, cbBuf); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif #ifdef CSP_USE_RC4 case CALG_RC4: if (pbData == NULL) { dwReturn = ERROR_SUCCESS; goto ErrorExit; } if (*pcbData > cbBuf) { dwReturn = ERROR_MORE_DATA; goto ErrorExit; } rc4((struct RC4_KEYSTRUCT *)pKey->pData, *pcbData, pbData); if (fFinal) { if (pKey->pData) _nt_free (pKey->pData, pKey->cbDataLen); pKey->pData = 0; pKey->cbDataLen = 0; } break; #endif #ifdef CSP_USE_AES case CALG_AES_128: case CALG_AES_192: case CALG_AES_256: dwSts = BlockEncrypt(aes, pKey, pKey->dwBlockLen, fFinal, pbData, pcbData, cbBuf); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } break; #endif default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } dwReturn = ERROR_SUCCESS; ErrorExit: return dwReturn; } /* - LocalEncrypt - * Purpose: * Encrypt data * * * Parameters: * IN hUID - Handle to the CSP user * IN hKey - Handle to the key * IN hHash - Optional handle to a hash * IN Final - Boolean indicating if this is the final * block of plaintext * IN OUT pbData - Data to be encrypted * IN OUT pdwDataLen - Pointer to the length of the data to be * encrypted * IN dwBufLen - Size of Data buffer * IN fIsExternal - Flag to tell if the call is for internal * CSP use or external caller * * Returns: */ DWORD LocalEncrypt( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN HCRYPTHASH hHash, IN BOOL Final, IN DWORD dwFlags, IN OUT BYTE *pbData, IN OUT DWORD *pdwDataLen, IN DWORD dwBufSize, IN BOOL fIsExternal) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD dwDataLen; PNTAGUserList pTmpUser; PNTAGKeyList pTmpKey; PNTAGKeyList pTmpKey2; PNTAGHashList pTmpHash; DWORD dwLen; MACstate *pMAC; BSAFE_PUB_KEY *pBsafePubKey; BYTE *pbOutput = NULL; DWORD dwSts; if (0 != (dwFlags & ~CRYPT_OAEP)) // && (0x9C580000 != dwFlags)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } dwDataLen = *pdwDataLen; if ((Final == FALSE) && (dwDataLen == 0)) { // If no data to encrypt and this isn't the last block, // then we're done. (if Final, we need to pad) dwReturn = ERROR_SUCCESS; goto ErrorExit; } pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; } // // Check if encryption allowed // if (fIsExternal && (PROV_RSA_SCHANNEL != pTmpUser->dwProvType) && ((pTmpUser->Rights & CRYPT_DISABLE_CRYPT) == CRYPT_DISABLE_CRYPT)) { dwReturn = (DWORD)NTE_PERM; goto ErrorExit; } dwSts = NTLValidate(hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts= NTLValidate(hKey, hUID, EXCHPUBKEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { // NTLValidate doesn't know what error to set // so it set NTE_FAIL -- fix it up. dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; } } if ((pTmpKey->Algid != CALG_RSA_KEYX) && (!FIsLegalKey(pTmpUser, pTmpKey, FALSE))) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } if ((Final == FALSE) && (pTmpKey->Algid != CALG_RC4)) { if (dwDataLen < pTmpKey->dwBlockLen) { *pdwDataLen = pTmpKey->dwBlockLen; dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } } if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) && (fDEncrypt && pbData != NULL && *pdwDataLen != 0)) { if (memcmp(dbDEncrypt, pbData, DE_BLOCKLEN) == 0) { dwReturn = (DWORD)NTE_DOUBLE_ENCRYPT; goto ErrorExit; } } // Check if we should do an auto-inflate if ((pTmpKey->pData == NULL) && (pTmpKey->Algid != CALG_RSA_KEYX)) { dwSts = InflateKey(pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } if ((hHash != 0) && (NULL != pbData)) { dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; } if (pTmpHash->Algid == CALG_MAC) { // Check if we should do an auto-inflate pMAC = pTmpHash->pHashData; dwSts = NTLValidate(pTmpHash->hKey, hUID, KEY_HANDLE, &pTmpKey2); if (ERROR_SUCCESS != dwSts) { // NTLValidate doesn't know what error to set // so it set NTE_FAIL -- fix it up. dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; } if (pTmpKey2->pData == NULL) { dwSts = InflateKey(pTmpKey2); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } } if (!CPHashData(hUID, hHash, pbData, *pdwDataLen, 0)) { dwReturn = GetLastError(); goto ErrorExit; } } // determine which algorithm is to be used switch (pTmpKey->Algid) { case CALG_RSA_KEYX: pBsafePubKey = (BSAFE_PUB_KEY *) pTmpKey->pKeyValue; if (pBsafePubKey == NULL) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } // compute length of resulting data dwLen = (pBsafePubKey->bitlen + 7) / 8; if (!CheckDataLenForRSAEncrypt(dwLen, *pdwDataLen, dwFlags)) { dwReturn = (DWORD)NTE_BAD_LEN; goto ErrorExit; } if (pbData == NULL || dwBufSize < dwLen) { *pdwDataLen = dwLen; // set what we need dwReturn = (pbData == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA; goto ErrorExit; } pbOutput = (BYTE*)_nt_malloc(dwLen); if (NULL == pbOutput) { dwReturn =ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } // perform the RSA encryption dwSts = RSAEncrypt(pTmpUser, pBsafePubKey, pbData, *pdwDataLen, pTmpKey->pbParams, pTmpKey->cbParams, dwFlags, pbOutput); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } *pdwDataLen = dwLen; memcpy(pbData, pbOutput, *pdwDataLen); break; default: dwSts = SymEncrypt(pTmpKey, Final, pbData, pdwDataLen, dwBufSize); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) && (pbData != NULL && *pdwDataLen >= DE_BLOCKLEN)) { memcpy(dbDEncrypt, pbData, DE_BLOCKLEN); fDEncrypt = TRUE; } else { fDEncrypt = FALSE; } dwReturn = ERROR_SUCCESS; ErrorExit: if (pbOutput) _nt_free(pbOutput, dwLen); return dwReturn; } /* - CPEncrypt - * Purpose: * Encrypt data * * * Parameters: * IN hUID - Handle to the CSP user * IN hKey - Handle to the key * IN hHash - Optional handle to a hash * IN Final - Boolean indicating if this is the final * block of plaintext * IN dwFlags - Flags values * IN OUT pbData - Data to be encrypted * IN OUT pdwDataLen - Pointer to the length of the data to be * encrypted * IN dwBufLen - Size of Data buffer * * Returns: */ BOOL WINAPI CPEncrypt( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN HCRYPTHASH hHash, IN BOOL Final, IN DWORD dwFlags, IN OUT BYTE *pbData, IN OUT DWORD *pdwDataLen, IN DWORD dwBufSize) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD dwSts; DWORD fRet; EntryPoint dwSts = LocalEncrypt(hUID, hKey, hHash, Final, dwFlags, pbData, pdwDataLen, dwBufSize, TRUE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } dwReturn = ERROR_SUCCESS; ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; } /* - SymDecrypt - * Purpose: * Decrypt data with symmetric algorithms. This function is used * by the LocalDecrypt function as well as the UnWrapSymKey (nt_key.c) * function. * * Parameters: * IN pKey - Handle to the key * IN pHash - Handle to a hash if needed * IN fFinal - Boolean indicating if this is the final * block of plaintext * IN OUT pbData - Data to be decrypted * IN OUT pcbData - Pointer to the length of the data to be * decrypted * * Returns: */ DWORD SymDecrypt( IN PNTAGKeyList pKey, IN PNTAGHashList pHash, IN BOOL fFinal, IN OUT BYTE *pbData, IN OUT DWORD *pcbData) { DWORD dwReturn = ERROR_INTERNAL_ERROR; MACstate *pMAC; DWORD dwSts; // determine which algorithm is to be used switch (pKey->Algid) { #ifdef CSP_USE_RC2 // the decryption is to be done with the RC2 algorithm case CALG_RC2: dwSts = BlockDecrypt(RC2, pKey, RC2_BLOCKLEN, fFinal, pbData, pcbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } if ((fFinal) && (NULL != pHash) && (pHash->Algid == CALG_MAC) && (pKey->Mode == CRYPT_MODE_CBC)) { pMAC = (MACstate *)pHash->pHashData; memcpy(pMAC->Feedback, pKey->FeedBack, RC2_BLOCKLEN); pHash->dwHashState |= DATA_IN_HASH; } break; #endif #ifdef CSP_USE_DES // the decryption is to be done with DES case CALG_DES: dwSts = BlockDecrypt(des, pKey, DES_BLOCKLEN, fFinal, pbData, pcbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } if ((fFinal) && (NULL != pHash) && (pHash->Algid == CALG_MAC) && (pKey->Mode == CRYPT_MODE_CBC)) { pMAC = (MACstate *)pHash->pHashData; memcpy(pMAC->Feedback, pKey->FeedBack, DES_BLOCKLEN); pHash->dwHashState |= DATA_IN_HASH; } break; #endif #ifdef CSP_USE_3DES // the decryption is to be done with the triple DES case CALG_3DES_112: case CALG_3DES: dwSts = BlockDecrypt(tripledes, pKey, DES_BLOCKLEN, fFinal, pbData, pcbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } if ((fFinal) && (NULL != pHash) && (pHash->Algid == CALG_MAC) && (pKey->Mode == CRYPT_MODE_CBC)) { pMAC = (MACstate *)pHash->pHashData; memcpy(pMAC->Feedback, pKey->FeedBack, DES_BLOCKLEN); pHash->dwHashState |= DATA_IN_HASH; } break; #endif #ifdef CSP_USE_RC4 case CALG_RC4: rc4((struct RC4_KEYSTRUCT *)pKey->pData, *pcbData, pbData); if (fFinal) { _nt_free (pKey->pData, pKey->cbDataLen); pKey->pData = 0; pKey->cbDataLen = 0; } break; #endif #ifdef CSP_USE_AES case CALG_AES_128: case CALG_AES_192: case CALG_AES_256: dwSts = BlockDecrypt(aes, pKey, pKey->dwBlockLen, fFinal, pbData, pcbData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } if ((fFinal) && (NULL != pHash) && (pHash->Algid == CALG_MAC) && (pKey->Mode == CRYPT_MODE_CBC)) { pMAC = (MACstate *)pHash->pHashData; memcpy(pMAC->Feedback, pKey->FeedBack, pKey->dwBlockLen); pHash->dwHashState |= DATA_IN_HASH; } break; #endif default: dwReturn = (DWORD)NTE_BAD_ALGID; goto ErrorExit; } dwReturn = ERROR_SUCCESS; ErrorExit: return dwReturn; } /* - LocalDecrypt - * Purpose: * Decrypt data * * * Parameters: * IN hUID - Handle to the CSP user * IN hKey - Handle to the key * IN hHash - Optional handle to a hash * IN Final - Boolean indicating if this is the final * block of ciphertext * IN dwFlags - Flags values * IN OUT pbData - Data to be decrypted * IN OUT pdwDataLen - Pointer to the length of the data to be * decrypted * IN fIsExternal - Flag to tell if the call is for internal * CSP use or external caller * * Returns: */ DWORD LocalDecrypt( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN HCRYPTHASH hHash, IN BOOL Final, IN DWORD dwFlags, IN OUT BYTE *pbData, IN OUT DWORD *pdwDataLen, IN BOOL fIsExternal) { DWORD dwReturn = ERROR_INTERNAL_ERROR; PNTAGUserList pTmpUser; PNTAGKeyList pTmpKey; PNTAGKeyList pTmpKey2; MACstate *pMAC; PNTAGHashList pTmpHash = NULL; BSAFE_PRV_KEY *pBsafePrvKey = NULL; BYTE *pbNewData = NULL; DWORD cbNewData; DWORD dwSts; if (0 != (dwFlags & ~CRYPT_OAEP)) // && (0x9C580000 != dwFlags)) { dwReturn = (DWORD)NTE_BAD_FLAGS; goto ErrorExit; } // We're done if decrypting 0 bytes. if (*pdwDataLen == 0) { dwReturn = (Final == TRUE) ? (DWORD)NTE_BAD_LEN : ERROR_SUCCESS; goto ErrorExit; } pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE); if (NULL == pTmpUser) { dwReturn = (DWORD)NTE_BAD_UID; goto ErrorExit; } // // Check if decryption allowed // if (fIsExternal && (PROV_RSA_SCHANNEL != pTmpUser->dwProvType) && ((pTmpUser->Rights & CRYPT_DISABLE_CRYPT) == CRYPT_DISABLE_CRYPT)) { dwReturn = (DWORD)NTE_PERM; goto ErrorExit; } // Check the key against the user. dwSts = NTLValidate(hKey, hUID, KEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { dwSts = NTLValidate(hKey, hUID, EXCHPUBKEY_HANDLE, &pTmpKey); if (ERROR_SUCCESS != dwSts) { // NTLValidate doesn't know what error to set // so it set NTE_FAIL -- fix it up. dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; } } if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) && fDDecrypt) { if (memcmp(dbDDecrypt, pbData, DE_BLOCKLEN) == 0) { dwReturn = (DWORD)NTE_DOUBLE_ENCRYPT; goto ErrorExit; } } if ((pTmpKey->Algid != CALG_RSA_KEYX) && (!FIsLegalKey(pTmpUser, pTmpKey, TRUE))) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } // Check if we should do an auto-inflate if ((pTmpKey->pData == NULL) && (pTmpKey->Algid != CALG_RSA_KEYX)) { dwSts = InflateKey(pTmpKey); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } // determine which algorithm is to be used switch (pTmpKey->Algid) { case CALG_RSA_KEYX: // check if the public key matches the private key if (pTmpUser->ContInfo.pbExchPub == NULL) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; } if ((pTmpUser->ContInfo.ContLens.cbExchPub != pTmpKey->cbKeyLen) || memcmp(pTmpUser->ContInfo.pbExchPub, pTmpKey->pKeyValue, pTmpUser->ContInfo.ContLens.cbExchPub)) { dwReturn = (DWORD)NTE_BAD_KEY; goto ErrorExit; } // if using protected store then load the key now dwSts = UnprotectPrivKey(pTmpUser, g_Strings.pwszImportSimple, FALSE, FALSE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; // NTE_BAD_KEYSET goto ErrorExit; } pBsafePrvKey = (BSAFE_PRV_KEY *)pTmpUser->pExchPrivKey; if (NULL == pBsafePrvKey) { dwReturn = (DWORD)NTE_NO_KEY; goto ErrorExit; } // perform the RSA decryption dwSts= RSADecrypt(pTmpUser, pBsafePrvKey, pbData, *pdwDataLen, pTmpKey->pbParams, pTmpKey->cbParams, dwFlags, &pbNewData, &cbNewData); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } *pdwDataLen = cbNewData; memcpy(pbData, pbNewData, *pdwDataLen); break; default: dwSts = SymDecrypt(pTmpKey, NULL, Final, pbData, pdwDataLen); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } if (hHash != 0) { dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash); if (ERROR_SUCCESS != dwSts) { dwReturn = (NTE_FAIL == dwSts) ? (DWORD)NTE_BAD_HASH : dwSts; goto ErrorExit; } if (pTmpHash->Algid == CALG_MAC) { // Check if we should do an auto-inflate pMAC = pTmpHash->pHashData; dwSts = NTLValidate(pTmpHash->hKey, hUID, KEY_HANDLE, &pTmpKey2); if (ERROR_SUCCESS != dwSts) { // NTLValidate doesn't know what error to set // so it set NTE_FAIL -- fix it up. dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts; goto ErrorExit; } if (pTmpKey2->pData == NULL) { dwSts = InflateKey(pTmpKey2); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } } if (!CPHashData(hUID, hHash, pbData, *pdwDataLen, 0)) { dwReturn = GetLastError(); goto ErrorExit; } } if ((POLICY_MS_DEF == pTmpUser->dwCspTypeId) && (*pdwDataLen >= DE_BLOCKLEN)) { memcpy(dbDDecrypt, pbData, DE_BLOCKLEN); fDDecrypt = TRUE; } else { fDDecrypt = FALSE; } dwReturn = ERROR_SUCCESS; ErrorExit: if (pbNewData) _nt_free(pbNewData, cbNewData); return dwReturn; } /* - CPDecrypt - * Purpose: * Decrypt data * * * Parameters: * IN hUID - Handle to the CSP user * IN hKey - Handle to the key * IN hHash - Optional handle to a hash * IN Final - Boolean indicating if this is the final * block of ciphertext * IN dwFlags - Flags values * IN OUT pbData - Data to be decrypted * IN OUT pdwDataLen - Pointer to the length of the data to be * decrypted * * Returns: */ BOOL WINAPI CPDecrypt( IN HCRYPTPROV hUID, IN HCRYPTKEY hKey, IN HCRYPTHASH hHash, IN BOOL Final, IN DWORD dwFlags, IN OUT BYTE *pbData, IN OUT DWORD *pdwDataLen) { DWORD dwReturn = ERROR_INTERNAL_ERROR; BOOL fRet; DWORD dwSts; EntryPoint dwSts = LocalDecrypt(hUID, hKey, hHash, Final, dwFlags, pbData, pdwDataLen, TRUE); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } dwReturn = ERROR_SUCCESS; ErrorExit: fRet = (ERROR_SUCCESS == dwReturn); if (!fRet) SetLastError(dwReturn); return fRet; }