From 4474004b8870445db720857fdb4d64d855fa3c1b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 13 May 2022 14:45:30 -0500 Subject: [PATCH] rsaenh: Store key state in hash data for _MAC hash algorithm. Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard --- 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());