From: Piotr Caban piotr@codeweavers.com
--- dlls/bcrypt/bcrypt.spec | 1 + dlls/bcrypt/bcrypt_main.c | 56 ++++++++++++++++++++++++++++++++++---- dlls/bcrypt/tests/bcrypt.c | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 6 deletions(-)
diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec index 90ab7b52fef..4f481b0bd30 100644 --- a/dlls/bcrypt/bcrypt.spec +++ b/dlls/bcrypt/bcrypt.spec @@ -35,6 +35,7 @@ @ stdcall BCryptHashData(ptr ptr long long) @ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) @ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long) +@ stdcall BCryptKeyDerivation(ptr ptr ptr long ptr long) @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) @ stub BCryptQueryContextConfiguration @ stub BCryptQueryContextFunctionConfiguration diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 0ca6e55e867..556e96700cf 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -2605,18 +2605,18 @@ static NTSTATUS derive_key_raw( struct secret *secret, UCHAR *output, ULONG outp return status; }
-static BCRYPT_ALG_HANDLE get_hash_handle( BCryptBuffer *buf ) +static BCRYPT_ALG_HANDLE get_hash_handle( BCryptBuffer *buf, BOOL hmac ) { const WCHAR *str = buf->pvBuffer;
if (!wcscmp( str, BCRYPT_SHA1_ALGORITHM )) - return BCRYPT_SHA1_ALG_HANDLE; + return hmac ? BCRYPT_HMAC_SHA1_ALG_HANDLE : BCRYPT_SHA1_ALG_HANDLE; if (!wcscmp( str, BCRYPT_SHA256_ALGORITHM )) - return BCRYPT_SHA256_ALG_HANDLE; + return hmac ? BCRYPT_HMAC_SHA256_ALG_HANDLE : BCRYPT_SHA256_ALG_HANDLE; if (!wcscmp( str, BCRYPT_SHA384_ALGORITHM )) - return BCRYPT_SHA384_ALG_HANDLE; + return hmac ? BCRYPT_HMAC_SHA384_ALG_HANDLE : BCRYPT_SHA384_ALG_HANDLE; if (!wcscmp( str, BCRYPT_SHA512_ALGORITHM )) - return BCRYPT_SHA512_ALG_HANDLE; + return hmac ? BCRYPT_HMAC_SHA512_ALG_HANDLE : BCRYPT_SHA512_ALG_HANDLE;
FIXME( "hash algorithm %s not supported\n", debugstr_w(str) ); return NULL; @@ -2637,7 +2637,7 @@ static NTSTATUS derive_key_hash( struct secret *secret, BCryptBufferDesc *desc, { if (desc->pBuffers[i].BufferType == KDF_HASH_ALGORITHM) { - alg = get_alg_object( get_hash_handle( desc->pBuffers + i )); + alg = get_alg_object( get_hash_handle( desc->pBuffers + i, FALSE )); if (!alg) return STATUS_NOT_SUPPORTED; } else FIXME( "buffer type %lu not supported\n", desc->pBuffers[i].BufferType ); @@ -2697,6 +2697,50 @@ NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, return STATUS_NOT_SUPPORTED; }
+NTSTATUS WINAPI BCryptKeyDerivation( BCRYPT_KEY_HANDLE handle, BCryptBufferDesc *desc, + UCHAR *output, ULONG output_size, ULONG *ret_len, ULONG flags ) +{ + struct key *key = get_key_object( handle ); + BCRYPT_ALG_HANDLE hash_alg = NULL; + ULONGLONG iter_count = 10000; + ULONG salt_size = 0; + UCHAR *salt = NULL; + NTSTATUS status; + ULONG i; + + TRACE( "%p, %p, %p, %lu, %p, %#lx\n", key, desc, output, output_size, ret_len, flags ); + + if (!key || !desc || !ret_len) return STATUS_INVALID_PARAMETER; + if (key->alg_id != ALG_ID_PBKDF2) + { + FIXME("unsupported key %d\n", key->alg_id); + return STATUS_NOT_IMPLEMENTED; + } + + for (i = 0; i < desc->cBuffers; i++) + { + switch (desc->pBuffers[i].BufferType) + { + case KDF_HASH_ALGORITHM: + hash_alg = get_hash_handle( desc->pBuffers + i, TRUE ); + break; + case KDF_SALT: + salt = desc->pBuffers[i].pvBuffer; + salt_size = desc->pBuffers[i].cbBuffer; + break; + case KDF_ITERATION_COUNT: + if (desc->pBuffers[i].cbBuffer != sizeof(ULONGLONG)) return STATUS_INVALID_PARAMETER; + iter_count = *(ULONGLONG *)desc->pBuffers[i].pvBuffer; + break; + } + } + + status = BCryptDeriveKeyPBKDF2( hash_alg, key->u.s.secret, key->u.s.secret_len, + salt, salt_size, iter_count, output, output_size, flags ); + if (!status) *ret_len = output_size; + return status; +} + BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { switch (reason) diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 272819d3335..2ca0eb3ab91 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -29,6 +29,8 @@ #include "wine/test.h"
static NTSTATUS (WINAPI *pBCryptHash)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG, UCHAR *, ULONG, UCHAR *, ULONG); +static NTSTATUS (WINAPI *pBCryptKeyDerivation)(BCRYPT_KEY_HANDLE, + BCryptBufferDesc *, UCHAR *, ULONG, ULONG *, ULONG);
static void test_BCryptGenRandom(void) { @@ -4372,11 +4374,46 @@ static void test_RC4(void)
static void test_PBKDF2(void) { + static char salt[] = "cCxuHMEHLibcglJOG88dIw=="; + static ULONGLONG iter_count = 25; + static BCryptBuffer pbkdf2_param_buffers[] = + { + { + sizeof(BCRYPT_SHA1_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA1_ALGORITHM, + }, + { + sizeof(salt) - 1, + KDF_SALT, + salt, + }, + { + sizeof(iter_count), + KDF_ITERATION_COUNT, + (void *)&iter_count, + } + }; + static BCryptBufferDesc pbkdf2_params = + { + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(pbkdf2_param_buffers), + pbkdf2_param_buffers, + }; + static UCHAR pbkdf2_hash[] = + { + 0x18, 0xf2, 0x58, 0x0b, 0x92, 0x6e, 0x6d, 0xfe, + 0x55, 0xbb, 0x62, 0x87, 0x5b, 0x1f, 0x61, 0x83, + 0x4d, 0x16, 0xe4, 0x04, 0xcd, 0xab, 0x43, 0x77, + 0x25, 0x3e, 0x1d, 0xb4, 0x95, 0x5f, 0xf7, 0x01, + }; + BCRYPT_KEY_LENGTHS_STRUCT key_lengths; BCRYPT_ALG_HANDLE alg; BCRYPT_KEY_HANDLE key; NTSTATUS status; ULONG val, size; + static BYTE buf[32];
status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_PBKDF2_ALGORITHM, NULL, 0); if (status == STATUS_NOT_FOUND) @@ -4385,6 +4422,7 @@ static void test_PBKDF2(void) return; } ok(!status, "got %#lx\n", status); + ok(pBCryptKeyDerivation != NULL, "BCryptKeyDerivation not available\n");
val = size = 0; status = BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, (UCHAR *)&val, sizeof(val), &size, 0); @@ -4413,6 +4451,23 @@ static void test_PBKDF2(void) ok(!status, "got %#lx\n", status); ok(val == strlen("test") * 8, "got %lu\n", val);
+ status = pBCryptKeyDerivation(key, &pbkdf2_params, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + + buf[0] = buf[1] = 'x'; + status = pBCryptKeyDerivation(key, &pbkdf2_params, buf, 1, &size, 0); + ok(!status, "got %#lx\n", status); + ok(size == 1, "size = %lu\n", size); + ok(buf[0] == pbkdf2_hash[0], "buf[0] = %x\n", buf[0]); + ok(buf[1] == 'x', "buf[1] = %x\n", buf[1]); + + memset(buf, 'x', sizeof(buf)); + status = pBCryptKeyDerivation(key, &pbkdf2_params, buf, sizeof(buf), &size, 0); + ok(!status, "got %#lx\n", status); + ok(size == sizeof(buf), "size = %lu\n", size); + ok(!memcmp(buf, pbkdf2_hash, sizeof(pbkdf2_hash)), + "wrong data (%s)\n", wine_dbgstr_an((char *)buf, size)); + status = BCryptDestroyKey(key); ok(!status, "got %#lx\n", status); status = BCryptCloseAlgorithmProvider(alg, 0); @@ -4430,6 +4485,7 @@ START_TEST(bcrypt) return; } pBCryptHash = (void *)GetProcAddress(module, "BCryptHash"); + pBCryptKeyDerivation = (void *)GetProcAddress(module, "BCryptKeyDerivation");
test_BCryptGenRandom(); test_BCryptGetFipsAlgorithmMode();