Paul Gofman : rsaenh: Store key state in hash data for _MAC hash algorithm.

Alexandre Julliard julliard at winehq.org
Mon May 16 15:37:59 CDT 2022


Module: wine
Branch: master
Commit: 4474004b8870445db720857fdb4d64d855fa3c1b
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=4474004b8870445db720857fdb4d64d855fa3c1b

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Fri May 13 14:45:30 2022 -0500

rsaenh: Store key state in hash data for _MAC hash algorithm.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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());




More information about the wine-cvs mailing list