diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec index 95bec876b97..90ab7b52fef 100644 --- a/dlls/bcrypt/bcrypt.spec +++ b/dlls/bcrypt/bcrypt.spec @@ -8,6 +8,7 @@ @ stdcall BCryptDecrypt(ptr ptr long ptr ptr long ptr long ptr long) @ stub BCryptDeleteContext @ stdcall BCryptDeriveKey(ptr wstr ptr ptr long ptr long) +@ stdcall BCryptDeriveKeyCapi(ptr ptr ptr long long) @ stdcall BCryptDeriveKeyPBKDF2(ptr ptr long ptr long int64 ptr long long) @ stdcall BCryptDestroyHash(ptr) @ stdcall BCryptDestroyKey(ptr) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 5f0b9f1ca8f..63117008800 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1609,6 +1609,53 @@ NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHA } } +#define HMAC_PAD_LEN 64 +NTSTATUS WINAPI BCryptDeriveKeyCapi( BCRYPT_HASH_HANDLE handle, BCRYPT_ALG_HANDLE halg, UCHAR *key, ULONG keylen, ULONG flags ) +{ + struct hash *hash = handle; + UCHAR buf[MAX_HASH_OUTPUT_BYTES * 2]; + NTSTATUS status; + ULONG len; + + TRACE( "%p, %p, %p, %u, %08x\n", handle, halg, key, keylen, flags ); + + if (!key || !keylen) return STATUS_INVALID_PARAMETER; + if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE; + if (keylen > builtin_algorithms[hash->alg_id].hash_length * 2) return STATUS_INVALID_PARAMETER; + + if (halg) + { + FIXME( "algorithm handle not supported\n" ); + return STATUS_NOT_IMPLEMENTED; + } + + len = builtin_algorithms[hash->alg_id].hash_length; + if ((status = BCryptFinishHash( handle, buf, len, 0 ))) return status; + + if (len < keylen) + { + UCHAR pad1[HMAC_PAD_LEN], pad2[HMAC_PAD_LEN]; + ULONG i; + + for (i = 0; i < sizeof(pad1); i++) + { + pad1[i] = 0x36 ^ (i < len ? buf[i] : 0); + pad2[i] = 0x5c ^ (i < len ? buf[i] : 0); + } + + if ((status = prepare_hash( hash )) || + (status = BCryptHashData( handle, pad1, sizeof(pad1), 0 )) || + (status = BCryptFinishHash( handle, buf, len, 0 ))) return status; + + if ((status = prepare_hash( hash )) || + (status = BCryptHashData( handle, pad2, sizeof(pad2), 0 )) || + (status = BCryptFinishHash( handle, buf + len, len, 0 ))) return status; + } + + memcpy( key, buf, keylen ); + return STATUS_SUCCESS; +} + static NTSTATUS pbkdf2( BCRYPT_HASH_HANDLE handle, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len, ULONGLONG iterations, ULONG i, UCHAR *dst, ULONG hash_len ) { diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index f7404057fa8..e64e78546d3 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -32,6 +32,7 @@ static NTSTATUS (WINAPI *pBCryptCreateHash)(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDL ULONG, ULONG); static NTSTATUS (WINAPI *pBCryptDecrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG *, ULONG); +static NTSTATUS (WINAPI *pBCryptDeriveKeyCapi)(BCRYPT_HASH_HANDLE, BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG); static NTSTATUS (WINAPI *pBCryptDeriveKeyPBKDF2)(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, PUCHAR, ULONG, ULONGLONG, PUCHAR, ULONG, ULONG); static NTSTATUS (WINAPI *pBCryptDestroyHash)(BCRYPT_HASH_HANDLE); @@ -2356,6 +2357,71 @@ static void test_aes_vector(void) ok(!ret, "got %08x\n", ret); } +static void test_BcryptDeriveKeyCapi(void) +{ + static const UCHAR expect[] = + {0xda,0x39,0xa3,0xee,0x5e,0x6b,0x4b,0x0d,0x32,0x55,0xbf,0xef,0x95,0x60,0x18,0x90,0xaf,0xd8,0x07,0x09}; + static const UCHAR expect2[] = + {0x9b,0x03,0x17,0x41,0xf4,0x75,0x11,0xac,0xff,0x22,0xee,0x40,0xbb,0xe8,0xf9,0x74,0x17,0x26,0xb6,0xf2, + 0xf8,0xc7,0x88,0x02,0x9a,0xdc,0x0d,0xd7,0x83,0x58,0xea,0x65,0x2e,0x8b,0x85,0xc6,0xdb,0xb7,0xed,0x1c}; + BCRYPT_ALG_HANDLE alg; + BCRYPT_HASH_HANDLE hash; + UCHAR key[40]; + NTSTATUS ret; + + ret = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA1_ALGORITHM, NULL, 0); + ok(!ret, "got %08x\n", ret); + + ret = pBCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0); + ok(!ret || broken(ret == STATUS_INVALID_PARAMETER) /* win2k8 */, "got %08x\n", ret); + if (ret == STATUS_INVALID_PARAMETER) + { + win_skip( "broken BCryptCreateHash\n" ); + return; + } + + ret = pBCryptDeriveKeyCapi(NULL, NULL, NULL, 0, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret); + + ret = pBCryptDeriveKeyCapi(hash, NULL, NULL, 0, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret); + + ret = pBCryptDeriveKeyCapi(hash, NULL, key, 0, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret); + + ret = pBCryptDeriveKeyCapi(hash, NULL, key, 41, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret); + + memset(key, 0, sizeof(key)); + ret = pBCryptDeriveKeyCapi(hash, NULL, key, 20, 0); + ok(!ret, "got %08x\n", ret); + ok(!memcmp(key, expect, sizeof(expect) - 1), "wrong key data\n"); + + ret = pBCryptDeriveKeyCapi(hash, NULL, key, 20, 0); + todo_wine ok(ret == STATUS_INVALID_HANDLE, "got %08x\n", ret); + + ret = pBCryptHashData(hash, NULL, 0, 0); + todo_wine ok(ret == STATUS_INVALID_HANDLE, "got %08x\n", ret); + + ret = pBCryptDestroyHash(hash); + ok(!ret, "got %08x\n", ret); + + ret = pBCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0); + ok(!ret, "got %08x\n", ret); + + ret = pBCryptHashData(hash, (UCHAR *)"test", 4, 0); + ok(!ret, "got %08x\n", ret); + + /* padding */ + memset(key, 0, sizeof(key)); + ret = pBCryptDeriveKeyCapi(hash, NULL, key, 40, 0); + ok(!ret, "got %08x\n", ret); + ok(!memcmp(key, expect2, sizeof(expect2) - 1), "wrong key data\n"); + + ret = pBCryptCloseAlgorithmProvider(alg, 0); + ok(!ret, "got %08x\n", ret); +} + START_TEST(bcrypt) { HMODULE module; @@ -2370,6 +2436,7 @@ START_TEST(bcrypt) pBCryptCloseAlgorithmProvider = (void *)GetProcAddress(module, "BCryptCloseAlgorithmProvider"); pBCryptCreateHash = (void *)GetProcAddress(module, "BCryptCreateHash"); pBCryptDecrypt = (void *)GetProcAddress(module, "BCryptDecrypt"); + pBCryptDeriveKeyCapi = (void *)GetProcAddress(module, "BCryptDeriveKeyCapi"); pBCryptDeriveKeyPBKDF2 = (void *)GetProcAddress(module, "BCryptDeriveKeyPBKDF2"); pBCryptDestroyHash = (void *)GetProcAddress(module, "BCryptDestroyHash"); pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey"); @@ -2418,6 +2485,7 @@ START_TEST(bcrypt) test_BCryptSignHash(); test_BCryptEnumAlgorithms(); test_aes_vector(); + test_BcryptDeriveKeyCapi(); FreeLibrary(module); } diff --git a/dlls/ncrypt/ncrypt.spec b/dlls/ncrypt/ncrypt.spec index 3908cbfb910..2b5a4fca420 100644 --- a/dlls/ncrypt/ncrypt.spec +++ b/dlls/ncrypt/ncrypt.spec @@ -8,7 +8,7 @@ @ stdcall BCryptDecrypt(ptr ptr long ptr ptr long ptr long ptr long) bcrypt.BCryptDecrypt @ stub BCryptDeleteContext @ stdcall BCryptDeriveKey(ptr wstr ptr ptr long ptr long) bcrypt.BCryptDeriveKey -@ stub BCryptDeriveKeyCapi +@ stdcall BCryptDeriveKeyCapi(ptr ptr ptr long long) bcrypt.BCryptDeriveKeyCapi @ stdcall BCryptDeriveKeyPBKDF2(ptr ptr long ptr long int64 ptr long long) bcrypt.BCryptDeriveKeyPBKDF2 @ stdcall BCryptDestroyHash(ptr) bcrypt.BCryptDestroyHash @ stdcall BCryptDestroyKey(ptr) bcrypt.BCryptDestroyKey diff --git a/include/bcrypt.h b/include/bcrypt.h index 3dcab5f75a2..62e6074f59b 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -348,6 +348,7 @@ NTSTATUS WINAPI BCryptCloseAlgorithmProvider(BCRYPT_ALG_HANDLE, ULONG); NTSTATUS WINAPI BCryptCreateHash(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDLE *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG); NTSTATUS WINAPI BCryptDecrypt(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG *, ULONG); NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE, LPCWSTR, BCryptBufferDesc*, PUCHAR, ULONG, ULONG *, ULONG); +NTSTATUS WINAPI BCryptDeriveKeyCapi(BCRYPT_HASH_HANDLE, BCRYPT_ALG_HANDLE, PUCHAR, ULONG, ULONG); NTSTATUS WINAPI BCryptDeriveKeyPBKDF2(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, PUCHAR, ULONG, ULONGLONG, PUCHAR, ULONG, ULONG); NTSTATUS WINAPI BCryptDestroyHash(BCRYPT_HASH_HANDLE); NTSTATUS WINAPI BCryptDestroyKey(BCRYPT_KEY_HANDLE);