diff --git a/dlls/advapi32/tests/crypt.c b/dlls/advapi32/tests/crypt.c index 99f113d6fb..2ffc62e51b 100644 --- a/dlls/advapi32/tests/crypt.c +++ b/dlls/advapi32/tests/crypt.c @@ -993,7 +993,6 @@ static void test_rc2_keylen(void) sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size, 0, CRYPT_IPSEC_HMAC_KEY, &hkey); /* CRYPT_IPSEC_HMAC_KEY is not supported on W2K and lower */ - todo_wine ok(ret || broken(!ret && GetLastError() == NTE_BAD_FLAGS), "CryptImportKey error %08x\n", GetLastError()); @@ -1041,7 +1040,6 @@ static void test_rc2_keylen(void) sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size, 0, CRYPT_IPSEC_HMAC_KEY, &hkey); /* CRYPT_IPSEC_HMAC_KEY is not supported on W2K and lower */ - todo_wine ok(ret || broken(!ret && GetLastError() == NTE_BAD_FLAGS), "CryptImportKey error %08x\n", GetLastError()); @@ -1066,7 +1064,6 @@ static void test_rc2_keylen(void) ret = pCryptImportKey(provider, (BYTE*)&key_blob, sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size, 0, CRYPT_IPSEC_HMAC_KEY, &hkey); - todo_wine ok(ret || broken(!ret && GetLastError() == NTE_BAD_FLAGS), "CryptImportKey error %08x\n", GetLastError()); @@ -1081,7 +1078,6 @@ static void test_rc2_keylen(void) ret = pCryptImportKey(provider, (BYTE*)&key_blob, sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size, 0, CRYPT_IPSEC_HMAC_KEY, &hkey); - todo_wine ok(ret || broken(!ret && GetLastError() == NTE_BAD_FLAGS), "CryptImportKey error %08x\n", GetLastError()); diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index 0f9959d5ad..50954c5986 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -74,7 +74,7 @@ typedef struct tagCRYPTHASH * CRYPTKEY - key objects */ #define RSAENH_MAGIC_KEY 0x73620457u -#define RSAENH_MAX_KEY_SIZE 48 +#define RSAENH_MAX_KEY_SIZE 64 #define RSAENH_MAX_BLOCK_SIZE 24 #define RSAENH_KEYSTATE_IDLE 0 #define RSAENH_KEYSTATE_ENCRYPTING 1 @@ -105,6 +105,7 @@ typedef struct tagCRYPTKEY BYTE abInitVector[RSAENH_MAX_BLOCK_SIZE]; BYTE abChainVector[RSAENH_MAX_BLOCK_SIZE]; RSAENH_SCHANNEL_INFO siSChannelInfo; + CRYPT_DATA_BLOB blobHmacKey; } CRYPTKEY; /****************************************************************************** @@ -732,6 +733,7 @@ static void destroy_key(OBJECTHDR *pObject) free_key_impl(pCryptKey->aiAlgid, &pCryptKey->context); free_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom); free_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom); + free_data_blob(&pCryptKey->blobHmacKey); HeapFree(GetProcessHeap(), 0, pCryptKey); } @@ -825,7 +827,13 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK return (HCRYPTKEY)INVALID_HANDLE_VALUE; } break; - + + case CALG_HMAC: + /* Avoid the key length check for HMAC keys, which have unlimited + * length. + */ + break; + default: if (dwKeyLen % 8 || dwKeyLen > peaAlgidInfo->dwMaxLen || @@ -859,6 +867,7 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK memset(pCryptKey->abInitVector, 0, sizeof(pCryptKey->abInitVector)); init_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom); init_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom); + init_data_blob(&pCryptKey->blobHmacKey); switch(aiAlgid) { @@ -892,6 +901,11 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK pCryptKey->dwBlockLen = dwKeyLen >> 3; pCryptKey->dwMode = 0; break; + + case CALG_HMAC: + pCryptKey->dwBlockLen = 0; + pCryptKey->dwMode = 0; + break; } *ppCryptKey = pCryptKey; @@ -2931,25 +2945,53 @@ static BOOL import_plaintext_key(HCRYPTPROV hProv, CONST BYTE *pbData, CONST DWORD *pKeyLen = (CONST DWORD *)(pBlobHeader + 1); CONST BYTE *pbKeyStream = (CONST BYTE*)(pKeyLen + 1); - if (dwFlags & CRYPT_IPSEC_HMAC_KEY) - { - FIXME("unimplemented for CRYPT_IPSEC_HMAC_KEY\n"); - SetLastError(NTE_BAD_FLAGS); - return FALSE; - } if (dwDataLen < sizeof(BLOBHEADER)+sizeof(DWORD)+*pKeyLen) { SetLastError(NTE_BAD_DATA); /* FIXME: error code */ return FALSE; } - *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, *pKeyLen<<19, &pCryptKey); - if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) - return FALSE; - memcpy(pCryptKey->abKeyValue, pbKeyStream, *pKeyLen); - setup_key(pCryptKey); - if (dwFlags & CRYPT_EXPORTABLE) - pCryptKey->dwPermissions |= CRYPT_EXPORT; + if (dwFlags & CRYPT_IPSEC_HMAC_KEY) + { + *phKey = new_key(hProv, CALG_HMAC, 0, &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) + return FALSE; + if (*pKeyLen <= sizeof(pCryptKey->abKeyValue)) + { + memcpy(pCryptKey->abKeyValue, pbKeyStream, *pKeyLen); + pCryptKey->dwKeyLen = *pKeyLen; + } + else + { + CRYPT_DATA_BLOB blobHmacKey = { *pKeyLen, (BYTE *)pbKeyStream }; + + /* In order to initialize an HMAC key, the key material is hashed, + * and the output of the hash function is used as the key material. + * Unfortunately, the way the Crypto API is designed, we don't know + * the hash algorithm yet, so we have to copy the entire key + * material. + */ + if (!copy_data_blob(&pCryptKey->blobHmacKey, &blobHmacKey)) + { + release_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY); + *phKey = (HCRYPTKEY)INVALID_HANDLE_VALUE; + return FALSE; + } + } + setup_key(pCryptKey); + if (dwFlags & CRYPT_EXPORTABLE) + pCryptKey->dwPermissions |= CRYPT_EXPORT; + } + else + { + *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, *pKeyLen<<19, &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) + return FALSE; + memcpy(pCryptKey->abKeyValue, pbKeyStream, *pKeyLen); + setup_key(pCryptKey); + if (dwFlags & CRYPT_EXPORTABLE) + pCryptKey->dwPermissions |= CRYPT_EXPORT; + } return TRUE; } @@ -4172,6 +4214,27 @@ BOOL WINAPI RSAENH_CPSetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwPa return FALSE; } + if (pCryptKey->aiAlgid == CALG_HMAC && !pCryptKey->dwKeyLen) { + HCRYPTHASH hKeyHash; + + if (!RSAENH_CPCreateHash(hProv, ((PHMAC_INFO)pbData)->HashAlgid, 0, 0, + &hKeyHash)) + return FALSE; + if (!RSAENH_CPHashData(hProv, hKeyHash, pCryptKey->blobHmacKey.pbData, + pCryptKey->blobHmacKey.cbData, 0)) + { + RSAENH_CPDestroyHash(hProv, hKeyHash); + return FALSE; + } + pCryptKey->dwKeyLen = sizeof(pCryptKey->abKeyValue); + if (!RSAENH_CPGetHashParam(hProv, hKeyHash, HP_HASHVAL, pCryptKey->abKeyValue, + &pCryptKey->dwKeyLen, 0)) + { + RSAENH_CPDestroyHash(hProv, hKeyHash); + return FALSE; + } + RSAENH_CPDestroyHash(hProv, hKeyHash); + } for (i=0; idwKeyLen,pCryptHash->pHMACInfo->cbInnerString); i++) { pCryptHash->pHMACInfo->pbInnerString[i] ^= pCryptKey->abKeyValue[i]; } diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index 844747cf2b..dd69c1d08e 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -2235,7 +2235,6 @@ static void test_import_hmac(void) *key_len = test_case->key_len; memcpy(key_bytes, test_case->key, *key_len); result = CryptImportKey(hProv, blob, size, 0, CRYPT_IPSEC_HMAC_KEY, &key); - todo_wine ok(result || broken(GetLastError() == NTE_BAD_FLAGS /* Win2k */), "CryptImportKey failed on test case %d: %08x\n", i, GetLastError()); if (result) { @@ -2253,7 +2252,7 @@ static void test_import_hmac(void) digest_size = sizeof(digest); result = CryptGetHashParam(hash, HP_HASHVAL, digest, &digest_size, 0); ok(result, "CryptGetHashParam failed on test case %d: %08x\n", i, GetLastError()); - ok(!memcmp(digest, test_case->digest, sizeof(digest)), "Unexpected valued on test case %d\n", i); + ok(!memcmp(digest, test_case->digest, sizeof(digest)), "Unexpected value on test case %d\n", i); CryptDestroyHash(hash); CryptDestroyKey(key); }