Part of the fix required Vivox chat server connection in "We Were Here Forever". It is actually patch 5 which is required specifically for the game, the rest are bugs found on the way of testing that functionality.
WRT the game, it also seems to depend on certain rsaenh functions clearing last error on success, I am going to send that part once this one is clear.
-- v2: rsaenh: Output FIXME when HMAC hash algorithm is not found. rsaenh: Allow importing bigger RC2 keys. rsaenh: Factor out alloc_key() function. rsaenh: Store key state in hash data for _MAC hash algorithm. rsaenh: Factor out block_encrypt() function. rsaenh: Handle uneven hash data updates sizes for CALG_MAC. rsaenh: Use CRT memory allocators.
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/handle.c | 11 ++++--- dlls/rsaenh/implglue.c | 15 ++++----- dlls/rsaenh/mpi.c | 15 ++++----- dlls/rsaenh/rsaenh.c | 71 +++++++++++++++++++++--------------------- 4 files changed, 58 insertions(+), 54 deletions(-)
diff --git a/dlls/rsaenh/handle.c b/dlls/rsaenh/handle.c index e9ec13f4ef4..88887b9f45f 100644 --- a/dlls/rsaenh/handle.c +++ b/dlls/rsaenh/handle.c @@ -23,6 +23,7 @@
#include <string.h> #include <stdarg.h> +#include <stdlib.h>
#include "windef.h" #include "winbase.h" @@ -70,7 +71,7 @@ void destroy_handle_table(struct handle_table *lpTable) { TRACE("(lpTable=%p)\n", lpTable);
- HeapFree(GetProcessHeap(), 0, lpTable->paEntries); + free(lpTable->paEntries); lpTable->mutex.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&lpTable->mutex); } @@ -139,14 +140,14 @@ static BOOL grow_handle_table(struct handle_table *lpTable)
newIEntries = lpTable->iEntries + TABLE_SIZE_INCREMENT;
- newEntries = HeapAlloc(GetProcessHeap(), 0, sizeof(struct handle_table_entry)*newIEntries); + newEntries = malloc(sizeof(struct handle_table_entry)*newIEntries); if (!newEntries) return FALSE;
if (lpTable->paEntries) { memcpy(newEntries, lpTable->paEntries, sizeof(struct handle_table_entry)*lpTable->iEntries); - HeapFree(GetProcessHeap(), 0, lpTable->paEntries); + free(lpTable->paEntries); }
for (i=lpTable->iEntries; i<newIEntries; i++) @@ -356,7 +357,7 @@ HCRYPTKEY new_object(struct handle_table *lpTable, size_t cbSize, DWORD dwType, if (ppObject) *ppObject = NULL;
- pObject = HeapAlloc(GetProcessHeap(), 0, cbSize); + pObject = malloc(cbSize); if (!pObject) return (HCRYPTKEY)INVALID_HANDLE_VALUE;
@@ -365,7 +366,7 @@ HCRYPTKEY new_object(struct handle_table *lpTable, size_t cbSize, DWORD dwType, pObject->destructor = destructor;
if (!alloc_handle(lpTable, pObject, &hObject)) - HeapFree(GetProcessHeap(), 0, pObject); + free(pObject); else if (ppObject) *ppObject = pObject; diff --git a/dlls/rsaenh/implglue.c b/dlls/rsaenh/implglue.c index d98a08b2f31..2bdbf3d7daf 100644 --- a/dlls/rsaenh/implglue.c +++ b/dlls/rsaenh/implglue.c @@ -23,6 +23,7 @@ */
#include <stdarg.h> +#include <stdlib.h> #include <stdio.h> #include "windef.h" #include "winbase.h" @@ -273,7 +274,7 @@ BOOL encrypt_block_impl(ALG_ID aiAlgid, DWORD dwKeySpec, KEY_CONTEXT *pKeyContex } reverse_bytes(out, outlen); } else { - in_reversed = HeapAlloc(GetProcessHeap(), 0, inlen); + in_reversed = malloc(inlen); if (!in_reversed) { SetLastError(NTE_NO_MEMORY); return FALSE; @@ -281,11 +282,11 @@ BOOL encrypt_block_impl(ALG_ID aiAlgid, DWORD dwKeySpec, KEY_CONTEXT *pKeyContex memcpy(in_reversed, in, inlen); reverse_bytes(in_reversed, inlen); if (rsa_exptmod(in_reversed, inlen, out, &outlen, dwKeySpec, &pKeyContext->rsa) != CRYPT_OK) { - HeapFree(GetProcessHeap(), 0, in_reversed); + free(in_reversed); SetLastError(NTE_FAIL); return FALSE; } - HeapFree(GetProcessHeap(), 0, in_reversed); + free(in_reversed); } break;
@@ -341,14 +342,14 @@ BOOL import_public_key_impl(const BYTE *pbSrc, KEY_CONTEXT *pKeyContext, DWORD d return FALSE; }
- pbTemp = HeapAlloc(GetProcessHeap(), 0, dwKeyLen); + pbTemp = malloc(dwKeyLen); if (!pbTemp) return FALSE; memcpy(pbTemp, pbSrc, dwKeyLen);
pKeyContext->rsa.type = PK_PUBLIC; reverse_bytes(pbTemp, dwKeyLen); mp_read_unsigned_bin(&pKeyContext->rsa.N, pbTemp, dwKeyLen); - HeapFree(GetProcessHeap(), 0, pbTemp); + free(pbTemp); mp_set_int(&pKeyContext->rsa.e, dwPubExp);
return TRUE; @@ -416,7 +417,7 @@ BOOL import_private_key_impl(const BYTE *pbSrc, KEY_CONTEXT *pKeyContext, DWORD return FALSE; }
- pbTemp = HeapAlloc(GetProcessHeap(), 0, 2*dwKeyLen+5*((dwKeyLen+1)>>1)); + pbTemp = malloc(2*dwKeyLen+5*((dwKeyLen+1)>>1)); if (!pbTemp) return FALSE; memcpy(pbTemp, pbSrc, min(dwDataLen, 2*dwKeyLen+5*((dwKeyLen+1)>>1))); pbBigNum = pbTemp; @@ -448,6 +449,6 @@ BOOL import_private_key_impl(const BYTE *pbSrc, KEY_CONTEXT *pKeyContext, DWORD mp_read_unsigned_bin(&pKeyContext->rsa.d, pbBigNum, dwKeyLen); mp_set_int(&pKeyContext->rsa.e, dwPubExp);
- HeapFree(GetProcessHeap(), 0, pbTemp); + free(pbTemp); return TRUE; } diff --git a/dlls/rsaenh/mpi.c b/dlls/rsaenh/mpi.c index 30cebc53039..f94693ad5e0 100644 --- a/dlls/rsaenh/mpi.c +++ b/dlls/rsaenh/mpi.c @@ -29,6 +29,7 @@ */
#include <stdarg.h> +#include <stdlib.h>
#include "windef.h" #include "winbase.h" @@ -119,7 +120,7 @@ static int mp_grow (mp_int * a, int size) * in case the operation failed we don't want * to overwrite the dp member of a. */ - tmp = HeapReAlloc(GetProcessHeap(), 0, a->dp, sizeof (mp_digit) * size); + tmp = realloc(a->dp, sizeof (mp_digit) * size); if (tmp == NULL) { /* reallocation failed but "a" is still valid [can be freed] */ return MP_MEM; @@ -204,7 +205,7 @@ static int mp_init (mp_int * a) int i;
/* allocate memory required and clear it */ - a->dp = HeapAlloc(GetProcessHeap(), 0, sizeof (mp_digit) * MP_PREC); + a->dp = malloc(sizeof (mp_digit) * MP_PREC); if (a->dp == NULL) { return MP_MEM; } @@ -232,7 +233,7 @@ static int mp_init_size (mp_int * a, int size) size += (MP_PREC * 2) - (size % MP_PREC);
/* alloc mem */ - a->dp = HeapAlloc(GetProcessHeap(), 0, sizeof (mp_digit) * size); + a->dp = malloc(sizeof (mp_digit) * size); if (a->dp == NULL) { return MP_MEM; } @@ -264,7 +265,7 @@ mp_clear (mp_int * a) }
/* free ram */ - HeapFree(GetProcessHeap(), 0, a->dp); + free(a->dp);
/* reset members to make debugging easier */ a->dp = NULL; @@ -3425,7 +3426,7 @@ int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback bsize = (size>>3)+((size&7)?1:0);
/* we need a buffer of bsize bytes */ - tmp = HeapAlloc(GetProcessHeap(), 0, bsize); + tmp = malloc(bsize); if (tmp == NULL) { return MP_MEM; } @@ -3490,7 +3491,7 @@ int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback
err = MP_OKAY; error: - HeapFree(GetProcessHeap(), 0, tmp); + free(tmp); return err; }
@@ -3712,7 +3713,7 @@ int mp_shrink (mp_int * a) { mp_digit *tmp; if (a->alloc != a->used && a->used > 0) { - if ((tmp = HeapReAlloc(GetProcessHeap(), 0, a->dp, sizeof (mp_digit) * a->used)) == NULL) { + if ((tmp = realloc(a->dp, sizeof (mp_digit) * a->used)) == NULL) { return MP_MEM; } a->dp = tmp; diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index a02b4f0ecad..f9513d0533e 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -23,6 +23,7 @@ */
#include <stdarg.h> +#include <stdlib.h> #include <stdio.h>
#include "windef.h" @@ -463,7 +464,7 @@ static inline const PROV_ENUMALGS_EX* get_algid_info(HCRYPTPROV hProv, ALG_ID al */ static inline BOOL copy_data_blob(PCRYPT_DATA_BLOB dst, const PCRYPT_DATA_BLOB src) { - dst->pbData = HeapAlloc(GetProcessHeap(), 0, src->cbData); + dst->pbData = malloc(src->cbData); if (!dst->pbData) { SetLastError(NTE_NO_MEMORY); return FALSE; @@ -494,7 +495,7 @@ static inline BOOL concat_data_blobs(PCRYPT_DATA_BLOB dst, const PCRYPT_DATA_BLO const PCRYPT_DATA_BLOB src2) { dst->cbData = src1->cbData + src2->cbData; - dst->pbData = HeapAlloc(GetProcessHeap(), 0, dst->cbData); + dst->pbData = malloc(dst->cbData); if (!dst->pbData) { SetLastError(NTE_NO_MEMORY); return FALSE; @@ -513,7 +514,7 @@ static inline BOOL concat_data_blobs(PCRYPT_DATA_BLOB dst, const PCRYPT_DATA_BLO * pBlob [I] Heap space occupied by pBlob->pbData is released */ static inline void free_data_blob(PCRYPT_DATA_BLOB pBlob) { - HeapFree(GetProcessHeap(), 0, pBlob->pbData); + free(pBlob->pbData); }
/****************************************************************************** @@ -537,9 +538,9 @@ static inline void init_data_blob(PCRYPT_DATA_BLOB pBlob) { */ static inline void free_hmac_info(PHMAC_INFO hmac_info) { if (!hmac_info) return; - HeapFree(GetProcessHeap(), 0, hmac_info->pbInnerString); - HeapFree(GetProcessHeap(), 0, hmac_info->pbOuterString); - HeapFree(GetProcessHeap(), 0, hmac_info); + free(hmac_info->pbInnerString); + free(hmac_info->pbOuterString); + free(hmac_info); }
/****************************************************************************** @@ -560,13 +561,13 @@ static inline void free_hmac_info(PHMAC_INFO hmac_info) { */ static BOOL copy_hmac_info(PHMAC_INFO *dst, const HMAC_INFO *src) { if (!src) return FALSE; - *dst = HeapAlloc(GetProcessHeap(), 0, sizeof(HMAC_INFO)); + *dst = malloc(sizeof(HMAC_INFO)); if (!*dst) return FALSE; **dst = *src; (*dst)->pbInnerString = NULL; (*dst)->pbOuterString = NULL; if ((*dst)->cbInnerString == 0) (*dst)->cbInnerString = RSAENH_HMAC_DEF_PAD_LEN; - (*dst)->pbInnerString = HeapAlloc(GetProcessHeap(), 0, (*dst)->cbInnerString); + (*dst)->pbInnerString = malloc((*dst)->cbInnerString); if (!(*dst)->pbInnerString) { free_hmac_info(*dst); return FALSE; @@ -576,7 +577,7 @@ static BOOL copy_hmac_info(PHMAC_INFO *dst, const HMAC_INFO *src) { else memset((*dst)->pbInnerString, RSAENH_HMAC_DEF_IPAD_CHAR, RSAENH_HMAC_DEF_PAD_LEN); if ((*dst)->cbOuterString == 0) (*dst)->cbOuterString = RSAENH_HMAC_DEF_PAD_LEN; - (*dst)->pbOuterString = HeapAlloc(GetProcessHeap(), 0, (*dst)->cbOuterString); + (*dst)->pbOuterString = malloc((*dst)->cbOuterString); if (!(*dst)->pbOuterString) { free_hmac_info(*dst); return FALSE; @@ -605,7 +606,7 @@ static void destroy_hash(OBJECTHDR *pObject) free_hmac_info(pCryptHash->pHMACInfo); free_data_blob(&pCryptHash->tpPRFParams.blobLabel); free_data_blob(&pCryptHash->tpPRFParams.blobSeed); - HeapFree(GetProcessHeap(), 0, pCryptHash); + free(pCryptHash); }
/****************************************************************************** @@ -669,12 +670,12 @@ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD break;
case CALG_MAC: - pbTemp = HeapAlloc(GetProcessHeap(), 0, dwDataLen); + pbTemp = malloc(dwDataLen); if (!pbTemp) return; memcpy(pbTemp, pbData, dwDataLen); RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0, pbTemp, &dwDataLen, dwDataLen); - HeapFree(GetProcessHeap(), 0, pbTemp); + free(pbTemp); break;
default: @@ -742,7 +743,7 @@ static void destroy_key(OBJECTHDR *pObject) free_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom); free_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom); free_data_blob(&pCryptKey->blobHmacKey); - HeapFree(GetProcessHeap(), 0, pCryptKey); + free(pCryptKey); }
/****************************************************************************** @@ -990,7 +991,7 @@ static void store_key_pair(HCRYPTKEY hCryptKey, HKEY hKey, DWORD dwKeySpec, DWOR { if (crypt_export_key(pKey, 0, PRIVATEKEYBLOB, 0, TRUE, 0, &dwLen)) { - pbKey = HeapAlloc(GetProcessHeap(), 0, dwLen); + pbKey = malloc(dwLen); if (pbKey) { if (crypt_export_key(pKey, 0, PRIVATEKEYBLOB, 0, TRUE, pbKey, @@ -1007,7 +1008,7 @@ static void store_key_pair(HCRYPTKEY hCryptKey, HKEY hKey, DWORD dwKeySpec, DWOR LocalFree(blobOut.pbData); } } - HeapFree(GetProcessHeap(), 0, pbKey); + free(pbKey); } } } @@ -1248,7 +1249,7 @@ static void destroy_key_container(OBJECTHDR *pObjectHdr) } else release_key_container_keys(pKeyContainer); - HeapFree( GetProcessHeap(), 0, pKeyContainer ); + free( pKeyContainer ); }
/****************************************************************************** @@ -1333,7 +1334,7 @@ static BOOL read_key_value(HCRYPTPROV hKeyContainer, HKEY hKey, DWORD dwKeySpec, if (RegQueryValueExA(hKey, szValueName, 0, &dwValueType, NULL, &dwLen) == ERROR_SUCCESS) { - pbKey = HeapAlloc(GetProcessHeap(), 0, dwLen); + pbKey = malloc(dwLen); if (pbKey) { if (RegQueryValueExA(hKey, szValueName, 0, &dwValueType, pbKey, &dwLen) == @@ -1350,7 +1351,7 @@ static BOOL read_key_value(HCRYPTPROV hKeyContainer, HKEY hKey, DWORD dwKeySpec, LocalFree(blobOut.pbData); } } - HeapFree(GetProcessHeap(), 0, pbKey); + free(pbKey); } } if (ret) @@ -1720,7 +1721,7 @@ static BOOL pkcs1_mgf1(HCRYPTPROV hProv, const BYTE *pbSeed, DWORD dwSeedLength, RSAENH_CPDestroyHash(hProv, hHash);
/* Allocate multiples of hash value */ - pbMask->pbData = HeapAlloc(GetProcessHeap(), 0, (dwLength + dwHashLen - 1) / dwHashLen * dwHashLen); + pbMask->pbData = malloc((dwLength + dwHashLen - 1) / dwHashLen * dwHashLen); if (!pbMask->pbData) { SetLastError(NTE_NO_MEMORY); @@ -1728,7 +1729,7 @@ static BOOL pkcs1_mgf1(HCRYPTPROV hProv, const BYTE *pbSeed, DWORD dwSeedLength, } pbMask->cbData = dwLength;
- pbHashInput = HeapAlloc(GetProcessHeap(), 0, dwSeedLength + sizeof(DWORD)); + pbHashInput = malloc(dwSeedLength + sizeof(DWORD)); if (!pbHashInput) { free_data_blob(pbMask); @@ -1752,7 +1753,7 @@ static BOOL pkcs1_mgf1(HCRYPTPROV hProv, const BYTE *pbSeed, DWORD dwSeedLength, RSAENH_CPDestroyHash(hProv, hHash); }
- HeapFree(GetProcessHeap(), 0, pbHashInput); + free(pbHashInput); return TRUE; }
@@ -1802,7 +1803,7 @@ static BOOL pad_data_oaep(HCRYPTPROV hProv, const BYTE *abData, DWORD dwDataLen, goto done; }
- pbPadded = HeapAlloc(GetProcessHeap(), 0, dwBufferLen); + pbPadded = malloc(dwBufferLen); if (!pbPadded) { SetLastError(NTE_NO_MEMORY); @@ -1843,7 +1844,7 @@ static BOOL pad_data_oaep(HCRYPTPROV hProv, const BYTE *abData, DWORD dwDataLen, ret = TRUE; done: RSAENH_CPDestroyHash(hProv, hHash); - HeapFree(GetProcessHeap(), 0, pbPadded); + free(pbPadded); free_data_blob(&blobDbMask); free_data_blob(&blobSeedMask); return ret; @@ -1958,7 +1959,7 @@ static BOOL unpad_data_oaep(HCRYPTPROV hProv, const BYTE *abData, DWORD dwDataLe }
/* Get default hash value */ - pbHashValue = HeapAlloc(GetProcessHeap(), 0, dwHashLen); + pbHashValue = malloc(dwHashLen); if (!pbHashValue) { SetLastError(NTE_NO_MEMORY); @@ -1968,7 +1969,7 @@ static BOOL unpad_data_oaep(HCRYPTPROV hProv, const BYTE *abData, DWORD dwDataLe RSAENH_CPGetHashParam(hProv, hHash, HP_HASHVAL, pbHashValue, &dwLen, 0);
/* Store seed and DB */ - pbBuffer = HeapAlloc(GetProcessHeap(), 0, dwDataLen - 1); + pbBuffer = malloc(dwDataLen - 1); if (!pbBuffer) { SetLastError(NTE_NO_MEMORY); @@ -2012,8 +2013,8 @@ static BOOL unpad_data_oaep(HCRYPTPROV hProv, const BYTE *abData, DWORD dwDataLe ret = TRUE; done: RSAENH_CPDestroyHash(hProv, hHash); - HeapFree(GetProcessHeap(), 0, pbHashValue); - HeapFree(GetProcessHeap(), 0, pbBuffer); + free(pbHashValue); + free(pbBuffer); free_data_blob(&blobDbMask); free_data_blob(&blobSeedMask); return ret; @@ -3227,25 +3228,25 @@ static BOOL import_symmetric_key(HCRYPTPROV hProv, const BYTE *pbData, DWORD dwD return FALSE; }
- pbDecrypted = HeapAlloc(GetProcessHeap(), 0, pPubKey->dwBlockLen); + pbDecrypted = malloc(pPubKey->dwBlockLen); if (!pbDecrypted) return FALSE; encrypt_block_impl(pPubKey->aiAlgid, PK_PRIVATE, &pPubKey->context, pbKeyStream, pbDecrypted, RSAENH_DECRYPT);
dwKeyLen = RSAENH_MAX_KEY_SIZE; if (!unpad_data(hProv, pbDecrypted, pPubKey->dwBlockLen, pbDecrypted, &dwKeyLen, dwFlags)) { - HeapFree(GetProcessHeap(), 0, pbDecrypted); + free(pbDecrypted); return FALSE; }
*phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey); if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) { - HeapFree(GetProcessHeap(), 0, pbDecrypted); + free(pbDecrypted); return FALSE; } memcpy(pCryptKey->abKeyValue, pbDecrypted, dwKeyLen); - HeapFree(GetProcessHeap(), 0, pbDecrypted); + free(pbDecrypted); setup_key(pCryptKey); if (dwFlags & CRYPT_EXPORTABLE) pCryptKey->dwPermissions |= CRYPT_EXPORT; @@ -4897,13 +4898,13 @@ BOOL WINAPI RSAENH_CPVerifySignature(HCRYPTPROV hProv, HCRYPTHASH hHash, const B dwHashLen = RSAENH_MAX_HASH_SIZE; if (!RSAENH_CPGetHashParam(hProv, hHash, HP_HASHVAL, abHashValue, &dwHashLen, 0)) return FALSE;
- pbConstructed = HeapAlloc(GetProcessHeap(), 0, dwSigLen); + pbConstructed = malloc(dwSigLen); if (!pbConstructed) { SetLastError(NTE_NO_MEMORY); goto cleanup; }
- pbDecrypted = HeapAlloc(GetProcessHeap(), 0, dwSigLen); + pbDecrypted = malloc(dwSigLen); if (!pbDecrypted) { SetLastError(NTE_NO_MEMORY); goto cleanup; @@ -4931,7 +4932,7 @@ BOOL WINAPI RSAENH_CPVerifySignature(HCRYPTPROV hProv, HCRYPTHASH hHash, const B SetLastError(NTE_BAD_SIGNATURE);
cleanup: - HeapFree(GetProcessHeap(), 0, pbConstructed); - HeapFree(GetProcessHeap(), 0, pbDecrypted); + free(pbConstructed); + free(pbDecrypted); return res; }
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/rsaenh.c | 59 ++++++++++++++++++++++++++++++++------ dlls/rsaenh/tests/rsaenh.c | 30 ++++++++++++++++++- 2 files changed, 79 insertions(+), 10 deletions(-)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index f9513d0533e..140fdec40d5 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -63,6 +63,7 @@ typedef struct tagCRYPTHASH BYTE abHashValue[RSAENH_MAX_HASH_SIZE]; PHMAC_INFO pHMACInfo; RSAENH_TLS1PRF_PARAMS tpPRFParams; + DWORD buffered_hash_bytes; } CRYPTHASH;
/****************************************************************************** @@ -661,6 +662,7 @@ static inline BOOL init_hash(CRYPTHASH *pCryptHash) { static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD dwDataLen) { BYTE *pbTemp; + DWORD len;
switch (pCryptHash->aiAlgid) { @@ -670,12 +672,49 @@ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD break;
case CALG_MAC: - pbTemp = malloc(dwDataLen); - if (!pbTemp) return; - memcpy(pbTemp, pbData, dwDataLen); - RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0, - pbTemp, &dwDataLen, dwDataLen); - free(pbTemp); + if (pCryptHash->buffered_hash_bytes) + { + len = min(pCryptHash->dwHashSize - pCryptHash->buffered_hash_bytes, dwDataLen); + memcpy(pCryptHash->abHashValue + pCryptHash->buffered_hash_bytes, pbData, len); + pbData += len; + dwDataLen -= len; + pCryptHash->buffered_hash_bytes += len; + if (pCryptHash->buffered_hash_bytes < pCryptHash->dwHashSize) + return; + pCryptHash->buffered_hash_bytes = 0; + len = pCryptHash->dwHashSize; + if (!RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0, + pCryptHash->abHashValue, &len, len)) + { + FIXME("RSAENH_CPEncrypt failed.\n"); + return; + } + } + len = dwDataLen - dwDataLen % pCryptHash->dwHashSize; + if (len) + { + pbTemp = malloc(len); + if (!pbTemp) + { + ERR("No memory.\n"); + return; + } + memcpy(pbTemp, pbData, len); + pbData += len; + dwDataLen -= len; + if (!RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0, + pbTemp, &len, len)) + { + FIXME("RSAENH_CPEncrypt failed.\n"); + return; + } + free(pbTemp); + } + if (dwDataLen) + { + memcpy(pCryptHash->abHashValue, pbData, dwDataLen); + pCryptHash->buffered_hash_bytes = dwDataLen; + } break;
default: @@ -715,9 +754,10 @@ static inline void finalize_hash(CRYPTHASH *pCryptHash) { break;
case CALG_MAC: - dwDataLen = 0; - RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, TRUE, 0, - pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize); + dwDataLen = pCryptHash->buffered_hash_bytes; + if (!RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, TRUE, 0, + pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize)) + FIXME("RSAENH_CPEncrypt failed.\n"); break;
default: @@ -2217,6 +2257,7 @@ BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, pCryptHash->pHMACInfo = NULL; pCryptHash->hash_handle = NULL; pCryptHash->dwHashSize = peaAlgidInfo->dwDefaultLen >> 3; + pCryptHash->buffered_hash_bytes = 0; init_data_blob(&pCryptHash->tpPRFParams.blobLabel); init_data_blob(&pCryptHash->tpPRFParams.blobSeed);
diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index f822c29bbc0..c9dbb72f427 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -1853,6 +1853,7 @@ static void test_mac(void) { DWORD dwLen; BYTE abData[256], abEnc[264]; static const BYTE mac_40[8] = { 0xb7, 0xa2, 0x46, 0xe9, 0x11, 0x31, 0xe0, 0xad}; + static const BYTE mac_40_2[8] = { 0xef, 0x22, 0x0a, 0x3b, 0xd0, 0xab, 0x48, 0x49}; int i;
for (i=0; i < ARRAY_SIZE(abData); i++) abData[i] = (BYTE)i; @@ -1876,7 +1877,34 @@ static void test_mac(void) { ok(result && dwLen == 8, "%08lx, dwLen: %ld\n", GetLastError(), dwLen);
ok(!memcmp(abData, mac_40, sizeof(mac_40)), "MAC failed!\n"); - + + for (i = 0; i < ARRAY_SIZE(abData); ++i) + abData[i] = (BYTE)i; + + result = CryptHashData(hHash, abData, 1, 0); + ok(!result && GetLastError() == NTE_BAD_HASH_STATE, "Unexpected result %d, error %#lx\n", result, GetLastError()); + + result = CryptDestroyHash(hHash); + ok(result, "%08lx\n", GetLastError()); + + result = CryptCreateHash(hProv, CALG_MAC, hKey, 0, &hHash); + ok(result, "%08lx\n", GetLastError()); + + result = CryptHashData(hHash, abData, 1, 0); + ok(result, "%08lx\n", GetLastError()); + result = CryptHashData(hHash, abData + 1, 1, 0); + ok(result, "%08lx\n", GetLastError()); + result = CryptHashData(hHash, abData + 2, 6, 0); + ok(result, "%08lx\n", GetLastError()); + result = CryptHashData(hHash, abData + 8, 9, 0); + ok(result, "%08lx\n", GetLastError()); + + dwLen = ARRAY_SIZE(abData); + result = CryptGetHashParam(hHash, HP_HASHVAL, abData, &dwLen, 0); + ok(result && dwLen == 8, "%08lx, dwLen %ld\n", GetLastError(), dwLen); + + ok(!memcmp(abData, mac_40_2, sizeof(mac_40)), "Hash does not match.\n"); + result = CryptDestroyHash(hHash); ok(result, "%08lx\n", GetLastError());
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/rsaenh.c | 124 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 54 deletions(-)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index 140fdec40d5..76122be2756 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -96,7 +96,7 @@ typedef struct tagCRYPTKEY DWORD dwSaltLen; DWORD dwBlockLen; DWORD dwState; - KEY_CONTEXT context; + KEY_CONTEXT context; BYTE abKeyValue[RSAENH_MAX_KEY_SIZE]; BYTE abInitVector[RSAENH_MAX_BLOCK_SIZE]; BYTE abChainVector[RSAENH_MAX_BLOCK_SIZE]; @@ -526,6 +526,73 @@ static inline void init_data_blob(PCRYPT_DATA_BLOB pBlob) { pBlob->cbData = 0; }
+/****************************************************************************** + * block_encrypt [Internal] + */ +BOOL block_encrypt(CRYPTKEY *key, BYTE *data, DWORD *data_len, DWORD buf_len, + BOOL final, KEY_CONTEXT *context, BYTE *chain_vector) +{ + BYTE *in, out[RSAENH_MAX_BLOCK_SIZE], o[RSAENH_MAX_BLOCK_SIZE]; + unsigned int encrypted_len, i, j, k; + + if (!final && (*data_len % key->dwBlockLen)) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + encrypted_len = (*data_len / key->dwBlockLen + (final ? 1 : 0)) * key->dwBlockLen; + + if (data == NULL) + { + *data_len = encrypted_len; + return TRUE; + } + if (encrypted_len > buf_len) + { + *data_len = encrypted_len; + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + /* Pad final block with length bytes */ + for (i = *data_len; i < encrypted_len; i++) data[i] = encrypted_len - *data_len; + *data_len = encrypted_len; + + for (i = 0, in = data; i < *data_len; i += key->dwBlockLen, in += key->dwBlockLen) + { + switch (key->dwMode) { + case CRYPT_MODE_ECB: + encrypt_block_impl(key->aiAlgid, 0, context, in, out, + RSAENH_ENCRYPT); + break; + case CRYPT_MODE_CBC: + for (j = 0; j < key->dwBlockLen; j++) + in[j] ^= chain_vector[j]; + encrypt_block_impl(key->aiAlgid, 0, context, in, out, + RSAENH_ENCRYPT); + memcpy(chain_vector, out, key->dwBlockLen); + break; + case CRYPT_MODE_CFB: + for (j = 0; j < key->dwBlockLen; j++) + { + encrypt_block_impl(key->aiAlgid, 0, context, + chain_vector, o, RSAENH_ENCRYPT); + out[j] = in[j] ^ o[0]; + for (k = 0; k < key->dwBlockLen - 1; k++) + chain_vector[k] = chain_vector[k+1]; + chain_vector[k] = out[j]; + } + break; + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + memcpy(in, out, key->dwBlockLen); + } + return TRUE; +} + /****************************************************************************** * free_hmac_info [Internal] * @@ -2515,8 +2582,6 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen) { CRYPTKEY *pCryptKey; - BYTE *in, out[RSAENH_MAX_BLOCK_SIZE], o[RSAENH_MAX_BLOCK_SIZE]; - DWORD dwEncryptedLen, i, j, k;
TRACE("(hProv=%08Ix, hKey=%08Ix, hHash=%08Ix, Final=%d, dwFlags=%08lx, pbData=%p, " "pdwDataLen=%p, dwBufLen=%ld)\n", hProv, hKey, hHash, Final, dwFlags, pbData, pdwDataLen, @@ -2554,58 +2619,9 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, }
if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_BLOCK) { - if (!Final && (*pdwDataLen % pCryptKey->dwBlockLen)) { - SetLastError(NTE_BAD_DATA); + if (!block_encrypt(pCryptKey, pbData, pdwDataLen, dwBufLen, Final, + &pCryptKey->context, pCryptKey->abChainVector)) return FALSE; - } - - dwEncryptedLen = (*pdwDataLen/pCryptKey->dwBlockLen+(Final?1:0))*pCryptKey->dwBlockLen; - - if (pbData == NULL) { - *pdwDataLen = dwEncryptedLen; - return TRUE; - } - else if (dwEncryptedLen > dwBufLen) { - *pdwDataLen = dwEncryptedLen; - SetLastError(ERROR_MORE_DATA); - return FALSE; - } - - /* Pad final block with length bytes */ - for (i=*pdwDataLen; i<dwEncryptedLen; i++) pbData[i] = dwEncryptedLen - *pdwDataLen; - *pdwDataLen = dwEncryptedLen; - - for (i=0, in=pbData; i<*pdwDataLen; i+=pCryptKey->dwBlockLen, in+=pCryptKey->dwBlockLen) { - switch (pCryptKey->dwMode) { - case CRYPT_MODE_ECB: - encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, in, out, - RSAENH_ENCRYPT); - break; - - case CRYPT_MODE_CBC: - for (j=0; j<pCryptKey->dwBlockLen; j++) in[j] ^= pCryptKey->abChainVector[j]; - encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, in, out, - RSAENH_ENCRYPT); - memcpy(pCryptKey->abChainVector, out, pCryptKey->dwBlockLen); - break; - - case CRYPT_MODE_CFB: - for (j=0; j<pCryptKey->dwBlockLen; j++) { - encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, - pCryptKey->abChainVector, o, RSAENH_ENCRYPT); - out[j] = in[j] ^ o[0]; - for (k=0; k<pCryptKey->dwBlockLen-1; k++) - pCryptKey->abChainVector[k] = pCryptKey->abChainVector[k+1]; - pCryptKey->abChainVector[k] = out[j]; - } - break; - - default: - SetLastError(NTE_BAD_ALGID); - return FALSE; - } - memcpy(in, out, pCryptKey->dwBlockLen); - } } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) { if (pbData == NULL) { *pdwDataLen = dwBufLen;
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/rsaenh.c | 72 +++++++++++++++++++++++--------------- dlls/rsaenh/tests/rsaenh.c | 27 ++++++++++++-- 2 files changed, 68 insertions(+), 31 deletions(-)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index 76122be2756..fd39a5b125e 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -39,6 +39,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+#define RSAENH_MAGIC_KEY 0x73620457u +#define RSAENH_MAX_KEY_SIZE 64 +#define RSAENH_MAX_BLOCK_SIZE 24 +#define RSAENH_KEYSTATE_IDLE 0 +#define RSAENH_KEYSTATE_ENCRYPTING 1 +#define RSAENH_KEYSTATE_MASTERKEY 2 + /****************************************************************************** * CRYPTHASH - hash objects */ @@ -64,17 +71,14 @@ typedef struct tagCRYPTHASH PHMAC_INFO pHMACInfo; RSAENH_TLS1PRF_PARAMS tpPRFParams; DWORD buffered_hash_bytes; + ALG_ID key_alg_id; + KEY_CONTEXT key_context; + BYTE abChainVector[RSAENH_MAX_BLOCK_SIZE]; } CRYPTHASH;
/****************************************************************************** * CRYPTKEY - key objects */ -#define RSAENH_MAGIC_KEY 0x73620457u -#define RSAENH_MAX_KEY_SIZE 64 -#define RSAENH_MAX_BLOCK_SIZE 24 -#define RSAENH_KEYSTATE_IDLE 0 -#define RSAENH_KEYSTATE_ENCRYPTING 1 -#define RSAENH_KEYSTATE_MASTERKEY 2 typedef struct _RSAENH_SCHANNEL_INFO { SCHANNEL_ALG saEncAlg; @@ -271,18 +275,6 @@ RSAENH_CPGetKeyParam( DWORD dwFlags );
-BOOL WINAPI -RSAENH_CPEncrypt( - HCRYPTPROV hProv, - HCRYPTKEY hKey, - HCRYPTHASH hHash, - BOOL Final, - DWORD dwFlags, - BYTE *pbData, - DWORD *pdwDataLen, - DWORD dwBufLen -); - BOOL WINAPI RSAENH_CPCreateHash( HCRYPTPROV hProv, @@ -674,6 +666,8 @@ static void destroy_hash(OBJECTHDR *pObject) free_hmac_info(pCryptHash->pHMACInfo); free_data_blob(&pCryptHash->tpPRFParams.blobLabel); free_data_blob(&pCryptHash->tpPRFParams.blobSeed); + if (pCryptHash->aiAlgid == CALG_MAC) + free_key_impl(pCryptHash->key_alg_id, &pCryptHash->key_context); free(pCryptHash); }
@@ -728,6 +722,7 @@ static inline BOOL init_hash(CRYPTHASH *pCryptHash) { */ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD dwDataLen) { + CRYPTKEY *key; BYTE *pbTemp; DWORD len;
@@ -739,6 +734,11 @@ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD break;
case CALG_MAC: + if (!lookup_handle(&handle_table, pCryptHash->hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&key)) + { + FIXME("Key lookup failed.\n"); + return; + } if (pCryptHash->buffered_hash_bytes) { len = min(pCryptHash->dwHashSize - pCryptHash->buffered_hash_bytes, dwDataLen); @@ -750,10 +750,10 @@ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD return; pCryptHash->buffered_hash_bytes = 0; len = pCryptHash->dwHashSize; - if (!RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0, - pCryptHash->abHashValue, &len, len)) + if (!block_encrypt(key, pCryptHash->abHashValue, &len, len, FALSE, + &pCryptHash->key_context, pCryptHash->abChainVector)) { - FIXME("RSAENH_CPEncrypt failed.\n"); + FIXME("block_encrypt failed.\n"); return; } } @@ -769,10 +769,10 @@ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD memcpy(pbTemp, pbData, len); pbData += len; dwDataLen -= len; - if (!RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0, - pbTemp, &len, len)) + if (!block_encrypt(key, pbTemp, &len, len, FALSE, + &pCryptHash->key_context, pCryptHash->abChainVector)) { - FIXME("RSAENH_CPEncrypt failed.\n"); + FIXME("block_encrypt failed.\n"); return; } free(pbTemp); @@ -798,8 +798,10 @@ static inline void update_hash(CRYPTHASH *pCryptHash, const BYTE *pbData, DWORD * PARAMS * pCryptHash [I] Hash object to be finalized. */ -static inline void finalize_hash(CRYPTHASH *pCryptHash) { +static inline void finalize_hash(CRYPTHASH *pCryptHash) +{ DWORD dwDataLen; + CRYPTKEY *key;
switch (pCryptHash->aiAlgid) { @@ -821,10 +823,15 @@ static inline void finalize_hash(CRYPTHASH *pCryptHash) { break;
case CALG_MAC: + if (!lookup_handle(&handle_table, pCryptHash->hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&key)) + { + FIXME("Key lookup failed.\n"); + return; + } dwDataLen = pCryptHash->buffered_hash_bytes; - if (!RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, TRUE, 0, - pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize)) - FIXME("RSAENH_CPEncrypt failed.\n"); + if (!block_encrypt(key, pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize, TRUE, + &pCryptHash->key_context, pCryptHash->abChainVector)) + FIXME("block_encrypt failed.\n"); break;
default: @@ -2264,7 +2271,7 @@ BOOL WINAPI RSAENH_CPAcquireContext(HCRYPTPROV *phProv, LPSTR pszContainer, BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) { - CRYPTKEY *pCryptKey; + CRYPTKEY *pCryptKey = NULL; CRYPTHASH *pCryptHash; const PROV_ENUMALGS_EX *peaAlgidInfo;
@@ -2319,6 +2326,13 @@ BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey,
pCryptHash->aiAlgid = Algid; pCryptHash->hKey = hKey; + if (Algid == CALG_MAC) + { + pCryptHash->key_alg_id = pCryptKey->aiAlgid; + setup_key(pCryptKey); + duplicate_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, &pCryptHash->key_context); + memcpy(pCryptHash->abChainVector, pCryptKey->abChainVector, sizeof(pCryptHash->abChainVector)); + } pCryptHash->hProv = hProv; pCryptHash->dwState = RSAENH_HASHSTATE_HASHING; pCryptHash->pHMACInfo = NULL; diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index c9dbb72f427..30c56722c12 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -1853,7 +1853,9 @@ static void test_mac(void) { DWORD dwLen; BYTE abData[256], abEnc[264]; static const BYTE mac_40[8] = { 0xb7, 0xa2, 0x46, 0xe9, 0x11, 0x31, 0xe0, 0xad}; + static const BYTE mac_40_old[8] = { 0x44, 0x78, 0x38, 0xad, 0x10, 0x13, 0x60, 0x8e}; static const BYTE mac_40_2[8] = { 0xef, 0x22, 0x0a, 0x3b, 0xd0, 0xab, 0x48, 0x49}; + static const BYTE mac_40_2_old[8] = { 0xa3, 0xf3, 0xfc, 0x70, 0xf4, 0xfa, 0xb0, 0x3e}; int i;
for (i=0; i < ARRAY_SIZE(abData); i++) abData[i] = (BYTE)i; @@ -1869,6 +1871,10 @@ static void test_mac(void) { ok(result, "%08lx\n", GetLastError()); if (!result) return;
+ dwLen = 8; + result = CryptEncrypt(hKey, 0, FALSE, 0, abEnc, &dwLen, dwLen); + ok(result, "%08lx\n", GetLastError()); + result = CryptHashData(hHash, abData, sizeof(abData), 0); ok(result, "%08lx\n", GetLastError());
@@ -1876,7 +1882,9 @@ static void test_mac(void) { result = CryptGetHashParam(hHash, HP_HASHVAL, abData, &dwLen, 0); ok(result && dwLen == 8, "%08lx, dwLen: %ld\n", GetLastError(), dwLen);
- ok(!memcmp(abData, mac_40, sizeof(mac_40)), "MAC failed!\n"); + /* Hash state is affected by key state before Win8. */ + ok(!memcmp(abData, mac_40, sizeof(mac_40)) || broken(!memcmp(abData, mac_40_old, sizeof(mac_40_old))), + "Hash does not match.\n");
for (i = 0; i < ARRAY_SIZE(abData); ++i) abData[i] = (BYTE)i; @@ -1890,8 +1898,17 @@ static void test_mac(void) { result = CryptCreateHash(hProv, CALG_MAC, hKey, 0, &hHash); ok(result, "%08lx\n", GetLastError());
+ dwLen = 8; + result = CryptEncrypt(hKey, 0, FALSE, 0, abEnc, &dwLen, dwLen); + ok(result, "%08lx\n", GetLastError()); + result = CryptHashData(hHash, abData, 1, 0); ok(result, "%08lx\n", GetLastError()); + + dwLen = 8; + result = CryptDecrypt(hKey, 0, FALSE, 0, abEnc, &dwLen); + ok(result, "%08lx\n", GetLastError()); + result = CryptHashData(hHash, abData + 1, 1, 0); ok(result, "%08lx\n", GetLastError()); result = CryptHashData(hHash, abData + 2, 6, 0); @@ -1899,11 +1916,17 @@ static void test_mac(void) { result = CryptHashData(hHash, abData + 8, 9, 0); ok(result, "%08lx\n", GetLastError());
+ dwLen = 8; + result = CryptDecrypt(hKey, 0, FALSE, 0, abEnc, &dwLen); + ok(result, "%08lx\n", GetLastError()); + dwLen = ARRAY_SIZE(abData); result = CryptGetHashParam(hHash, HP_HASHVAL, abData, &dwLen, 0); ok(result && dwLen == 8, "%08lx, dwLen %ld\n", GetLastError(), dwLen);
- ok(!memcmp(abData, mac_40_2, sizeof(mac_40)), "Hash does not match.\n"); + /* Hash state is affected by key state before Win8. */ + ok(!memcmp(abData, mac_40_2, sizeof(mac_40_2)) + || broken(!memcmp(abData, mac_40_2_old, sizeof(mac_40_2_old))), "Hash does not match.\n");
result = CryptDestroyHash(hHash); ok(result, "%08lx\n", GetLastError());
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/rsaenh.c | 166 +++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 79 deletions(-)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index fd39a5b125e..8a11da5f3f8 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -876,6 +876,92 @@ static inline void setup_key(CRYPTKEY *pCryptKey) { pCryptKey->abKeyValue); }
+/****************************************************************************** + * alloc_key [Internal] + * + */ +static HCRYPTKEY alloc_key(HCRYPTPROV hprov, ALG_ID alg_id, DWORD flags, DWORD key_len, CRYPTKEY **ret_key) +{ + KEYCONTAINER *key_container = get_key_container(hprov); + HCRYPTKEY hkey; + CRYPTKEY *key; + + hkey = new_object(&handle_table, sizeof(CRYPTKEY), RSAENH_MAGIC_KEY, + destroy_key, (OBJECTHDR**)&key); + if (hkey == (HCRYPTKEY)INVALID_HANDLE_VALUE) + return hkey; + + key->aiAlgid = alg_id; + key->hProv = hprov; + key->dwModeBits = 0; + key->dwPermissions = CRYPT_ENCRYPT | CRYPT_DECRYPT | CRYPT_READ | CRYPT_WRITE | CRYPT_MAC; + if (flags & CRYPT_EXPORTABLE) + key->dwPermissions |= CRYPT_EXPORT; + key->dwKeyLen = key_len >> 3; + key->dwEffectiveKeyLen = 0; + + /* + * For compatibility reasons a 40 bit key on the Enhanced + * provider will not have salt + */ + if (key_container->dwPersonality == RSAENH_PERSONALITY_ENHANCED + && (alg_id == CALG_RC2 || alg_id == CALG_RC4) + && (flags & CRYPT_CREATE_SALT) && key_len == 40) + key->dwSaltLen = 0; + else if ((flags & CRYPT_CREATE_SALT) || (key_len == 40 && !(flags & CRYPT_NO_SALT))) + key->dwSaltLen = 16 /*FIXME*/ - key->dwKeyLen; + else + key->dwSaltLen = 0; + memset(key->abKeyValue, 0, sizeof(key->abKeyValue)); + memset(key->abInitVector, 0, sizeof(key->abInitVector)); + memset(&key->siSChannelInfo.saEncAlg, 0, sizeof(key->siSChannelInfo.saEncAlg)); + memset(&key->siSChannelInfo.saMACAlg, 0, sizeof(key->siSChannelInfo.saMACAlg)); + init_data_blob(&key->siSChannelInfo.blobClientRandom); + init_data_blob(&key->siSChannelInfo.blobServerRandom); + init_data_blob(&key->blobHmacKey); + + switch(alg_id) + { + case CALG_PCT1_MASTER: + case CALG_SSL2_MASTER: + case CALG_SSL3_MASTER: + case CALG_TLS1_MASTER: + case CALG_RC4: + key->dwBlockLen = 0; + key->dwMode = 0; + break; + + case CALG_RC2: + case CALG_DES: + case CALG_3DES_112: + case CALG_3DES: + key->dwBlockLen = 8; + key->dwMode = CRYPT_MODE_CBC; + break; + + case CALG_AES_128: + case CALG_AES_192: + case CALG_AES_256: + key->dwBlockLen = 16; + key->dwMode = CRYPT_MODE_CBC; + break; + + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + key->dwBlockLen = key_len >> 3; + key->dwMode = 0; + break; + + case CALG_HMAC: + key->dwBlockLen = 0; + key->dwMode = 0; + break; + } + + *ret_key = key; + return hkey; +} + /****************************************************************************** * new_key [Internal] * @@ -896,8 +982,6 @@ static inline void setup_key(CRYPTKEY *pCryptKey) { */ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTKEY **ppCryptKey) { - HCRYPTKEY hCryptKey; - CRYPTKEY *pCryptKey; DWORD dwKeyLen = HIWORD(dwFlags); const PROV_ENUMALGS_EX *peaAlgidInfo;
@@ -969,83 +1053,7 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK } }
- hCryptKey = new_object(&handle_table, sizeof(CRYPTKEY), RSAENH_MAGIC_KEY, - destroy_key, (OBJECTHDR**)&pCryptKey); - if (hCryptKey != (HCRYPTKEY)INVALID_HANDLE_VALUE) - { - KEYCONTAINER *pKeyContainer = get_key_container(hProv); - pCryptKey->aiAlgid = aiAlgid; - pCryptKey->hProv = hProv; - pCryptKey->dwModeBits = 0; - pCryptKey->dwPermissions = CRYPT_ENCRYPT | CRYPT_DECRYPT | CRYPT_READ | CRYPT_WRITE | - CRYPT_MAC; - if (dwFlags & CRYPT_EXPORTABLE) - pCryptKey->dwPermissions |= CRYPT_EXPORT; - pCryptKey->dwKeyLen = dwKeyLen >> 3; - pCryptKey->dwEffectiveKeyLen = 0; - - /* - * For compatibility reasons a 40 bit key on the Enhanced - * provider will not have salt - */ - if (pKeyContainer->dwPersonality == RSAENH_PERSONALITY_ENHANCED - && (aiAlgid == CALG_RC2 || aiAlgid == CALG_RC4) - && (dwFlags & CRYPT_CREATE_SALT) && dwKeyLen == 40) - pCryptKey->dwSaltLen = 0; - else if ((dwFlags & CRYPT_CREATE_SALT) || (dwKeyLen == 40 && !(dwFlags & CRYPT_NO_SALT))) - pCryptKey->dwSaltLen = 16 /*FIXME*/ - pCryptKey->dwKeyLen; - else - pCryptKey->dwSaltLen = 0; - memset(pCryptKey->abKeyValue, 0, sizeof(pCryptKey->abKeyValue)); - memset(pCryptKey->abInitVector, 0, sizeof(pCryptKey->abInitVector)); - memset(&pCryptKey->siSChannelInfo.saEncAlg, 0, sizeof(pCryptKey->siSChannelInfo.saEncAlg)); - memset(&pCryptKey->siSChannelInfo.saMACAlg, 0, sizeof(pCryptKey->siSChannelInfo.saMACAlg)); - init_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom); - init_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom); - init_data_blob(&pCryptKey->blobHmacKey); - - switch(aiAlgid) - { - case CALG_PCT1_MASTER: - case CALG_SSL2_MASTER: - case CALG_SSL3_MASTER: - case CALG_TLS1_MASTER: - case CALG_RC4: - pCryptKey->dwBlockLen = 0; - pCryptKey->dwMode = 0; - break; - - case CALG_RC2: - case CALG_DES: - case CALG_3DES_112: - case CALG_3DES: - pCryptKey->dwBlockLen = 8; - pCryptKey->dwMode = CRYPT_MODE_CBC; - break; - - case CALG_AES_128: - case CALG_AES_192: - case CALG_AES_256: - pCryptKey->dwBlockLen = 16; - pCryptKey->dwMode = CRYPT_MODE_CBC; - break; - - case CALG_RSA_KEYX: - case CALG_RSA_SIGN: - pCryptKey->dwBlockLen = dwKeyLen >> 3; - pCryptKey->dwMode = 0; - break; - - case CALG_HMAC: - pCryptKey->dwBlockLen = 0; - pCryptKey->dwMode = 0; - break; - } - - *ppCryptKey = pCryptKey; - } - - return hCryptKey; + return alloc_key(hProv, aiAlgid, dwFlags, dwKeyLen, ppCryptKey); }
/******************************************************************************
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/rsaenh.c | 43 +++++++- dlls/rsaenh/tests/rsaenh.c | 218 +++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+), 1 deletion(-)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index 8a11da5f3f8..2dcc85cad7b 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -25,6 +25,7 @@ #include <stdarg.h> #include <stdlib.h> #include <stdio.h> +#include <assert.h>
#include "windef.h" #include "winbase.h" @@ -2627,6 +2628,23 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, return FALSE; }
+ if (pCryptKey->aiAlgid == CALG_RC2) + { + const PROV_ENUMALGS_EX *info; + + if (!(info = get_algid_info(hProv, pCryptKey->aiAlgid))) + { + FIXME("Can't get algid info.\n"); + SetLastError(NTE_BAD_KEY); + return FALSE; + } + if (pCryptKey->dwKeyLen > info->dwMaxLen / 8) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + } + if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) pCryptKey->dwState = RSAENH_KEYSTATE_ENCRYPTING;
@@ -3318,7 +3336,30 @@ static BOOL import_symmetric_key(HCRYPTPROV hProv, const BYTE *pbData, DWORD dwD return FALSE; }
- *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey); + if (pBlobHeader->aiKeyAlg == CALG_RC2) + { + const PROV_ENUMALGS_EX *info; + + info = get_algid_info(hProv, CALG_RC2); + assert(info); + if (!dwKeyLen) + dwKeyLen = info->dwDefaultLen; + if (dwKeyLen < info->dwMinLen / 8 || dwKeyLen > 128) + { + WARN("Invalid RC2 key, len %ld.\n", dwKeyLen); + *phKey = (HCRYPTKEY)INVALID_HANDLE_VALUE; + SetLastError(NTE_BAD_DATA); + } + else if ((*phKey = alloc_key(hProv, pBlobHeader->aiKeyAlg, 0, dwKeyLen << 3, &pCryptKey)) + != (HCRYPTKEY)INVALID_HANDLE_VALUE && info->dwDefaultLen == 40 && dwKeyLen > info->dwMaxLen / 8) + { + pCryptKey->dwEffectiveKeyLen = 40; + } + } + else + { + *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey); + } if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) { free(pbDecrypted); diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index 30c56722c12..6d784e2245d 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -3985,6 +3985,221 @@ err: } }
+static void test_rc2_import(void) +{ + static const DWORD test_lengths[] = { 128 + 8, 256, 512, 1024 }; + static const DWORD mac_results[ARRAY_SIZE(test_lengths)][2] = + { + {0xc13650cf, 0xa3e93efb}, + {0x6f7be248, 0x444b38b2}, + {0x2c3534d2, 0x29fca10c}, + {0x2c3534d2, 0x29fca10c}, + }; + static const DWORD mac_baseprov_results[ARRAY_SIZE(test_lengths)][2] = + { + {0x7e94a244, 0x12a9ae17}, + {0x2aaa6719, 0xa671d9a6}, + {0x2e730ce2, 0x9ebe6016}, + {0x2e730ce2, 0x9ebe6016}, + }; + static const DWORD mac_results_old[ARRAY_SIZE(test_lengths)][2] = + { + {0xebe2155a, 0xab2f58b7}, + {0x4394ccb2, 0xbe5c629b}, + {0xd7bc2195, 0x63fb2785}, + {0xd7bc2195, 0x63fb2785}, + }; + static const DWORD mac_baseprov_results_old[ARRAY_SIZE(test_lengths)][2] = + { + {0xe2ed2dec, 0x5ae837ed}, + {0x12f4b193, 0xe3f6afc1}, + {0x04d7f905, 0x686d357b}, + {0x04d7f905, 0x686d357b}, + }; + static const DWORD hmac_results[ARRAY_SIZE(test_lengths)][4] = + { + {0x2f44586d, 0x76d04c9f, 0xdae8fc03, 0x27e870bd}, + {0xbcde3186, 0xd9892cd5, 0x578c89f5, 0xc2cba8e5}, + {0xad2bf1cc, 0xae4e2c1f, 0xd1599a67, 0x0167d802}, + {0x6ee75968, 0x52a0eff5, 0x75340d85, 0x87b64962}, + }; + static const DWORD decrypt_baseprov_results[ARRAY_SIZE(test_lengths)][2] = + { + {0x48c4ff05, 0x9d880b90}, + {0xcfee0629, 0xfeab04a1}, + {0x23c9336c, 0x7f67b26e}, + {0x23c9336c, 0x7f67b26e}, + }; + static const DWORD decrypt_results[ARRAY_SIZE(test_lengths)][2] = + { + {0xb37e1be2, 0x1ed67048}, + {0x7c7d0b04, 0x3a74bb76}, + {0x7bfd232c, 0x93d52c4f}, + {0x7bfd232c, 0x93d52c4f}, + }; + + struct key_blob + { + BLOBHEADER h; + union + { + DWORD key_size; + DWORD alg_id; + } param; + BYTE data[512]; + } + key_data; + const DWORD *results, *broken_results; + HCRYPTKEY exchange_key, key; + DWORD len, value, expected; + DWORD test_length; + BYTE data[2048]; + HCRYPTPROV prov; + HCRYPTHASH hash; + unsigned int i; + HMAC_INFO hmac; + BOOL ret; + + ret = CryptAcquireContextA(&prov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + /* CryptGenKey() favours advertised key length limit. */ + ret = CryptGenKey(prov, CALG_RC2, 128 << 16, &key); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + CryptDestroyKey(key); + + ret = CryptGenKey(prov, CALG_RC2, (128 + 8) << 16, &key); + ok(!ret, "Expected failure.\n"); + + CryptReleaseContext(prov, 0); + + ret = CryptGetUserKey(hProv, AT_KEYEXCHANGE, &exchange_key); + ok(ret, "CryptGetUserKey failed.\n"); + + memset(&key_data.h, 0, sizeof(key_data.h)); + key_data.h.bVersion = CUR_BLOB_VERSION; + key_data.h.aiKeyAlg = CALG_RC2; + + for (i = 0; i < ARRAY_SIZE(test_lengths); ++i) + { + memset(key_data.data, 0xcc, sizeof(key_data.data)); + test_length = test_lengths[i]; + winetest_push_context("length %lu", test_length); + len = min(test_length / 8, 64); + + + ret = CryptEncrypt(exchange_key, 0, TRUE, 0, key_data.data, &len, sizeof(key_data) - 12); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + memset(key_data.data + len, 0xee, sizeof(key_data.data) - len); + + /* Importing a larger key as plaintext fails. */ + key_data.h.bType = PLAINTEXTKEYBLOB; + key_data.param.key_size = test_length / 8; + ret = CryptImportKey(hProv, (BYTE *)&key_data, offsetof(struct key_blob, data[test_length / 8]), 0, 0, &key); + ok(!ret, "Expected failure.\n"); + + /* Importing a larger key as SIMPLEBLOB succeeds. */ + key_data.h.bType = SIMPLEBLOB; + key_data.param.alg_id = CALG_RSA_KEYX; + ret = CryptImportKey(hProv, (BYTE *)&key_data, offsetof(struct key_blob, data[len]), + exchange_key, 0, &key); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + /* Effective key length is a public key decrypted length except for the base provider + * where it is default length. */ + len = sizeof(value); + value = 0xdeadbeef; + ret = CryptGetKeyParam(key, KP_EFFECTIVE_KEYLEN, (BYTE *)&value, &len, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + expected = BASE_PROV ? 40 : test_length; + expected = min(expected, 512); + ok(value == expected, "Unexpected value %lu, expected %lu.\n", value, expected); + + expected = min(test_length, 512); + ret = CryptGetKeyParam(key, KP_KEYLEN, (BYTE *)&value, &len, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + ok(value == expected, "Unexpected value %lu, expected %lu.\n", value, expected); + + /* The resulting key is not good for encryption. */ + memset(data, 0xcc, 8); + len = 8; + ret = CryptEncrypt(key, 0, FALSE, 0, data, &len, sizeof(data)); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == NTE_BAD_KEY, "Unexpected error %#lx.\n", GetLastError()); + len = 8; + ret = CryptEncrypt(key, 0, TRUE, 0, data, &len, sizeof(data)); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == NTE_BAD_KEY, "Unexpected error %#lx.\n", GetLastError()); + /* But decryption works. */ + len = 8; + ret = CryptDecrypt(key, 0, FALSE, 0, data, &len); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + ok(len == 8, "Unexpected len %lu.\n", len); + results = BASE_PROV ? decrypt_baseprov_results[i] : decrypt_results[i]; + ok(!memcmp(data, results, len), "Data does not match.\n"); + + ret = CryptCreateHash(hProv, CALG_MAC, key, 0, &hash); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + data[0] = 0; + ret = CryptHashData(hash, data, 1, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + len = sizeof(value); + ret = CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *)&value, &len, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + ok(value == 8, "Unexpected value %lu.\n", value); + + len = 32; + memset(data, 0xcc, 8); + ret = CryptGetHashParam(hash, HP_HASHVAL, data, &len, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + ok(len == 8, "Unexpected len %lu.\n", len); + + results = BASE_PROV ? mac_baseprov_results[i] : mac_results[i]; + broken_results = BASE_PROV ? mac_baseprov_results_old[i] : mac_results_old[i]; + /* Hash state is affected by key state before Win8. */ + ok(!memcmp(data, results, len) || broken(!memcmp(data, broken_results, len)), "Hash does not match.\n"); + + CryptDestroyHash(hash); + + ret = CryptCreateHash(hProv, CALG_HMAC, key, 0, &hash); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + memset(&hmac, 0, sizeof(hmac)); + hmac.HashAlgid = CALG_MD5; + memset(data, 0, sizeof(data)); + hmac.pbInnerString = data; + hmac.cbInnerString = test_length; + hmac.pbOuterString = data; + hmac.cbOuterString = test_length; + + ret = CryptSetHashParam(hash, HP_HMAC_INFO, (BYTE *)&hmac, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + data[0] = 0; + ret = CryptHashData(hash, data, 1, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + + len = sizeof(value); + ret = CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *)&value, &len, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + ok(value == 16, "Unexpected value %lu.\n", value); + + len = 16; + ret = CryptGetHashParam(hash, HP_HASHVAL, data, &len, 0); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + ok(len == 16, "Unexpected len %lu.\n", len); + + ok(!memcmp(data, hmac_results[i], len), "Hash does not match.\n"); + + CryptDestroyHash(hash); + CryptDestroyKey(key); + winetest_pop_context(); + } + CryptDestroyKey(exchange_key); +} + START_TEST(rsaenh) { for (iProv = 0; iProv < ARRAY_SIZE(szProviders); iProv++) @@ -4016,6 +4231,7 @@ START_TEST(rsaenh) test_import_hmac(); test_enum_container(); if(!BASE_PROV) test_key_derivation(STRONG_PROV ? "STRONG" : "ENH"); + test_rc2_import(); clean_up_base_environment(); }
@@ -4026,10 +4242,12 @@ START_TEST(rsaenh) test_rsa_round_trip(); if (!init_aes_environment()) return; + trace("Testing AES provider.\n"); test_aes(128); test_aes(192); test_aes(256); test_sha2(); test_key_derivation("AES"); + test_rc2_import(); clean_up_aes_environment(); }
From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/rsaenh/rsaenh.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index 2dcc85cad7b..beac3c7e850 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -690,7 +690,13 @@ static inline BOOL init_hash(CRYPTHASH *pCryptHash) { const PROV_ENUMALGS_EX *pAlgInfo;
pAlgInfo = get_algid_info(pCryptHash->hProv, pCryptHash->pHMACInfo->HashAlgid); - if (!pAlgInfo) return FALSE; + if (!pAlgInfo) + { + /* A number of hash algorithms (e. g., _SHA256) are supported for HMAC even for providers + * which don't list the algorithm, so print a fixme here. */ + FIXME("Hash algroithm %#x not found.\n", pCryptHash->pHMACInfo->HashAlgid); + return FALSE; + } pCryptHash->dwHashSize = pAlgInfo->dwDefaultLen >> 3; init_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->hash_handle); update_hash_impl(pCryptHash->hash_handle,
It turns out the bigger RC2 key import works with SIMPLEBLOB but not PLAINTEXTKEYBLOB, thus advapi32/crypt.c test failure. A bigger key import doesn't seem to work with other ciphers (I tried with _RC4 and AES).
v2 changes: - add tests for PLAINTEXTKEYBLOB import with bigger size to rsaenh; - factor out alloc_key() function and use that instead of new_key() in symmetric_key_import(). Now this RC2 specifics logic is gathered in symmetric_key_import() where it seems to belong except for CPEncrypt() part which still seems to require a special case check.
This merge request was approved by Hans Leidekker.