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.
From: 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
--- 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
--- 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
--- 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
--- dlls/rsaenh/rsaenh.c | 47 +++++++++ dlls/rsaenh/tests/rsaenh.c | 196 +++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+)
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index fd39a5b125e..909fcabd54f 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -957,6 +957,15 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK */ break;
+ case CALG_RC2: + if (dwKeyLen % 8 || dwKeyLen < peaAlgidInfo->dwMinLen) + { + WARN("Invalid RC2 key len %ld.\n", dwKeyLen); + SetLastError(NTE_BAD_DATA); + return (HCRYPTKEY)INVALID_HANDLE_VALUE; + } + break; + default: if (dwKeyLen % 8 || dwKeyLen > peaAlgidInfo->dwMaxLen || @@ -1016,6 +1025,9 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK break;
case CALG_RC2: + if (peaAlgidInfo->dwDefaultLen == 40 && dwKeyLen > peaAlgidInfo->dwMaxLen) + pCryptKey->dwEffectiveKeyLen = 40; + /* fallthrough */ case CALG_DES: case CALG_3DES_112: case CALG_3DES: @@ -2619,6 +2631,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;
@@ -3561,6 +3590,24 @@ BOOL WINAPI RSAENH_CPGenKey(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYP break;
case CALG_RC2: + { + const PROV_ENUMALGS_EX *info; + DWORD key_len = HIWORD(dwFlags); + + if (!(info = get_algid_info(hProv, Algid))) + { + SetLastError(NTE_BAD_ALGID); + *phKey = (HCRYPTKEY)INVALID_HANDLE_VALUE; + break; + } + if (key_len > info->dwMaxLen) + { + SetLastError(NTE_BAD_FLAGS); + *phKey = (HCRYPTKEY)INVALID_HANDLE_VALUE; + break; + } + } + /* fallthrough */ case CALG_RC4: case CALG_DES: case CALG_3DES_112: diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index 30c56722c12..0fe9dda449c 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -3985,6 +3985,199 @@ 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}, + }; + + const DWORD *results, *broken_results; + BYTE key_data[2048], data[2048]; + HCRYPTKEY exchange_key, key; + DWORD len, value, expected; + DWORD test_length; + 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"); + + ((DWORD *)key_data)[0] = 0x00000201; + ((DWORD *)key_data)[1] = CALG_RC2; + ((DWORD *)key_data)[2] = CALG_RSA_KEYX; + + for (i = 0; i < ARRAY_SIZE(test_lengths); ++i) + { + memset(key_data + 12, 0xcc, sizeof(key_data) - 12); + 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 + 12, &len, sizeof(key_data) - 12); + ok(ret, "Failed, error %#lx.\n", GetLastError()); + memset(key_data + 12 + len, 0xee, sizeof(key_data) - 12 - len); + + /* Importing a larger key succeeds. */ + ret = CryptImportKey(hProv, key_data, len + 12, 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 +4209,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 +4220,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(); }
On Fri, 2022-05-13 at 20:55 +0000, Paul Gofman wrote: From: Paul Gofman pgofman@codeweavers.com
--- dlls/rsaenh/rsaenh.c | 47 +++++++++ dlls/rsaenh/tests/rsaenh.c | 196 +++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+)
This causes a test failure:
crypt.c:1144: Test failed: unexpected error deadbeef make[1]: *** [Makefile:3290: dlls/advapi32/tests/crypt.ok] Error 1
From: 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 909fcabd54f..720a8d71751 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -689,7 +689,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,
The commits sign-off are missing, FWIW `git rebase --signoff` can do that automatically.