diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index c919c1d943a..ed1cab0f12a 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -23,6 +23,7 @@ #include #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H #include +#include #elif defined(SONAME_LIBGNUTLS) #include #include @@ -55,6 +56,9 @@ MAKE_FUNCPTR(gnutls_global_set_log_level); MAKE_FUNCPTR(gnutls_hash); MAKE_FUNCPTR(gnutls_hash_deinit); MAKE_FUNCPTR(gnutls_hash_init); +MAKE_FUNCPTR(gnutls_hmac); +MAKE_FUNCPTR(gnutls_hmac_deinit); +MAKE_FUNCPTR(gnutls_hmac_init); MAKE_FUNCPTR(gnutls_perror); #undef MAKE_FUNCPTR @@ -87,6 +91,9 @@ static BOOL gnutls_initialize(void) LOAD_FUNCPTR(gnutls_hash); LOAD_FUNCPTR(gnutls_hash_deinit); LOAD_FUNCPTR(gnutls_hash_init); + LOAD_FUNCPTR(gnutls_hmac); + LOAD_FUNCPTR(gnutls_hmac_deinit); + LOAD_FUNCPTR(gnutls_hmac_init); LOAD_FUNCPTR(gnutls_perror) #undef LOAD_FUNCPTR @@ -196,6 +203,7 @@ struct algorithm { struct object hdr; enum alg_id id; + BOOL hmac; }; NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags ) @@ -203,12 +211,14 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR struct algorithm *alg; enum alg_id alg_id; + const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG; + TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags ); if (!handle || !id) return STATUS_INVALID_PARAMETER; - if (flags) + if (flags & ~supported_flags) { - FIXME( "unimplemented flags %08x\n", flags ); + FIXME( "unsupported flags %08x\n", flags & ~supported_flags); return STATUS_NOT_IMPLEMENTED; } @@ -231,6 +241,7 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY; alg->hdr.magic = MAGIC_ALG; alg->id = alg_id; + alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG; *handle = alg; return STATUS_SUCCESS; @@ -263,12 +274,14 @@ struct hash { struct object hdr; enum alg_id alg_id; + BOOL hmac; union { CC_MD5_CTX md5_ctx; CC_SHA1_CTX sha1_ctx; CC_SHA256_CTX sha256_ctx; CC_SHA512_CTX sha512_ctx; + CCHmacContext hmac_ctx; } u; }; @@ -279,6 +292,7 @@ static NTSTATUS hash_init( struct hash *hash ) case ALG_ID_MD5: CC_MD5_Init( &hash->u.md5_ctx ); break; + case ALG_ID_SHA1: CC_SHA1_Init( &hash->u.sha1_ctx ); break; @@ -302,6 +316,41 @@ static NTSTATUS hash_init( struct hash *hash ) return STATUS_SUCCESS; } +static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size ) +{ + CCHmacAlgorithm cc_algorithm; + switch (hash->alg_id) + { + case ALG_ID_MD5: + cc_algorithm = kCCHmacAlgMD5; + break; + + case ALG_ID_SHA1: + cc_algorithm = kCCHmacAlgSHA1; + break; + + case ALG_ID_SHA256: + cc_algorithm = kCCHmacAlgSHA256; + break; + + case ALG_ID_SHA384: + cc_algorithm = kCCHmacAlgSHA384; + break; + + case ALG_ID_SHA512: + cc_algorithm = kCCHmacAlgSHA512; + break; + + default: + ERR( "unhandled id %u\n", hash->alg_id ); + return STATUS_NOT_IMPLEMENTED; + } + + CCHmacInit( &hash->u.hmac_ctx, cc_algorithm, key, key_size ); + return STATUS_SUCCESS; +} + + static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size ) { switch (hash->alg_id) @@ -333,6 +382,12 @@ static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size ) return STATUS_SUCCESS; } +static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size ) +{ + CCHmacUpdate( &hash->u.hmac_ctx, input, size ); + return STATUS_SUCCESS; +} + static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size ) { switch (hash->alg_id) @@ -363,12 +418,24 @@ static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size ) } return STATUS_SUCCESS; } + +static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size ) +{ + CCHmacFinal( &hash->u.hmac_ctx, output ); + + return STATUS_SUCCESS; +} #elif defined(HAVE_GNUTLS_HASH) struct hash { struct object hdr; enum alg_id alg_id; - gnutls_hash_hd_t handle; + BOOL hmac; + union + { + gnutls_hash_hd_t hash_handle; + gnutls_hmac_hd_t hmac_handle; + } u; }; static NTSTATUS hash_init( struct hash *hash ) @@ -403,25 +470,74 @@ static NTSTATUS hash_init( struct hash *hash ) return STATUS_NOT_IMPLEMENTED; } - if (pgnutls_hash_init( &hash->handle, alg )) return STATUS_INTERNAL_ERROR; + if (pgnutls_hash_init( &hash->u.hash_handle, alg )) return STATUS_INTERNAL_ERROR; + return STATUS_SUCCESS; +} + +static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size ) +{ + gnutls_mac_algorithm_t alg; + + if (!libgnutls_handle) return STATUS_INTERNAL_ERROR; + + switch (hash->alg_id) + { + case ALG_ID_MD5: + alg = GNUTLS_MAC_MD5; + break; + case ALG_ID_SHA1: + alg = GNUTLS_MAC_SHA1; + break; + + case ALG_ID_SHA256: + alg = GNUTLS_MAC_SHA256; + break; + + case ALG_ID_SHA384: + alg = GNUTLS_MAC_SHA384; + break; + + case ALG_ID_SHA512: + alg = GNUTLS_MAC_SHA512; + break; + + default: + ERR( "unhandled id %u\n", hash->alg_id ); + return STATUS_NOT_IMPLEMENTED; + } + + if (pgnutls_hmac_init( &hash->u.hmac_handle, alg, key, key_size )) return STATUS_INTERNAL_ERROR; return STATUS_SUCCESS; } static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size ) { - if (pgnutls_hash( hash->handle, input, size )) return STATUS_INTERNAL_ERROR; + if (pgnutls_hash( hash->u.hash_handle, input, size )) return STATUS_INTERNAL_ERROR; + return STATUS_SUCCESS; +} + +static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size ) +{ + if (pgnutls_hmac( hash->u.hmac_handle, input, size )) return STATUS_INTERNAL_ERROR; return STATUS_SUCCESS; } static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size ) { - pgnutls_hash_deinit( hash->handle, output ); + pgnutls_hash_deinit( hash->u.hash_handle, output ); + return STATUS_SUCCESS; +} + +static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size ) +{ + pgnutls_hmac_deinit( hash->u.hmac_handle, output ); return STATUS_SUCCESS; } #else struct hash { struct object hdr; + BOOL hmac; enum alg_id alg_id; }; @@ -431,17 +547,35 @@ static NTSTATUS hash_init( struct hash *hash ) return STATUS_NOT_IMPLEMENTED; } +static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size ) +{ + ERR( "support for hashes not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size ) { ERR( "support for hashes not available at build time\n" ); return STATUS_NOT_IMPLEMENTED; } +static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size ) +{ + ERR( "support for hashes not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size ) { ERR( "support for hashes not available at build time\n" ); return STATUS_NOT_IMPLEMENTED; } + +static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size ) +{ + ERR( "support for hashes not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} #endif #define OBJECT_LENGTH_MD5 274 @@ -604,7 +738,18 @@ NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDL if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY; hash->hdr.magic = MAGIC_HASH; hash->alg_id = alg->id; - if ((status = hash_init( hash )) != STATUS_SUCCESS) + hash->hmac = alg->hmac; + + if (hash->hmac) + { + status = hmac_init( hash, secret, secretlen ); + } + else + { + status = hash_init( hash ); + } + + if (status != STATUS_SUCCESS) { HeapFree( GetProcessHeap(), 0, hash ); return status; @@ -634,7 +779,14 @@ NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG s if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE; if (!input) return STATUS_SUCCESS; - return hash_update( hash, input, size ); + if (hash->hmac) + { + return hmac_update( hash, input, size ); + } + else + { + return hash_update( hash, input, size ); + } } NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags ) @@ -646,7 +798,14 @@ NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULON if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE; if (!output) return STATUS_INVALID_PARAMETER; - return hash_finish( hash, output, size ); + if (hash->hmac) + { + return hmac_finish( hash, output, size ); + } + else + { + return hash_finish( hash, output, size ); + } } BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index f1f000207d6..447861e8ff0 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -115,9 +115,10 @@ static void _test_alg_name(unsigned line, void *handle, const char *exname) static void test_sha1(void) { static const char expected[] = "961fa64958818f767707072755d7018dcd278e94"; + static const char expected_hmac[] = "2472cf65d0e090618d769d3e46f0d9446cf212da"; BCRYPT_ALG_HANDLE alg; BCRYPT_HASH_HANDLE hash; - UCHAR buf[512], sha1[20]; + UCHAR buf[512], buf_hmac[1024], sha1[20], sha1_hmac[20]; ULONG size, len; char str[41]; NTSTATUS ret; @@ -185,15 +186,46 @@ static void test_sha1(void) ret = BCryptCloseAlgorithmProvider(alg, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + alg = NULL; + ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA1_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(alg != NULL, "alg not set\n"); + + hash = NULL; + len = sizeof(buf_hmac); + ret = BCryptCreateHash(alg, &hash, buf_hmac, len, (UCHAR *)"key", sizeof("key"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(hash != NULL, "hash not set\n"); + + ret = BCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + test_hash_length(hash, 20); + test_alg_name(hash, "SHA1"); + + memset(sha1_hmac, 0, sizeof(sha1_hmac)); + ret = BCryptFinishHash(hash, sha1_hmac, sizeof(sha1_hmac), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + format_hash( sha1_hmac, sizeof(sha1_hmac), str ); + ok(!strcmp(str, expected_hmac), "got %s\n", str); + + ret = BCryptDestroyHash(hash); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + ret = BCryptCloseAlgorithmProvider(alg, 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); } static void test_sha256(void) { static const char expected[] = "ceb73749c899693706ede1e30c9929b3fd5dd926163831c2fb8bd41e6efb1126"; + static const char expected_hmac[] = + "34c1aa473a4468a91d06e7cdbc75bc4f93b830ccfc2a47ffd74e8e6ed29e4c72"; BCRYPT_ALG_HANDLE alg; BCRYPT_HASH_HANDLE hash; - UCHAR buf[512], sha256[32]; + UCHAR buf[512], buf_hmac[1024], sha256[32], sha256_hmac[32]; ULONG size, len; char str[65]; NTSTATUS ret; @@ -261,15 +293,46 @@ static void test_sha256(void) ret = BCryptCloseAlgorithmProvider(alg, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + alg = NULL; + ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(alg != NULL, "alg not set\n"); + + hash = NULL; + len = sizeof(buf_hmac); + ret = BCryptCreateHash(alg, &hash, buf_hmac, len, (UCHAR *)"key", sizeof("key"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(hash != NULL, "hash not set\n"); + + ret = BCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + test_hash_length(hash, 32); + test_alg_name(hash, "SHA256"); + + memset(sha256_hmac, 0, sizeof(sha256_hmac)); + ret = BCryptFinishHash(hash, sha256_hmac, sizeof(sha256_hmac), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + format_hash( sha256_hmac, sizeof(sha256_hmac), str ); + ok(!strcmp(str, expected_hmac), "got %s\n", str); + + ret = BCryptDestroyHash(hash); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + ret = BCryptCloseAlgorithmProvider(alg, 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); } static void test_sha384(void) { static const char expected[] = "62b21e90c9022b101671ba1f808f8631a8149f0f12904055839a35c1ca78ae5363eed1e743a692d70e0504b0cfd12ef9"; + static const char expected_hmac[] = + "4b3e6d6ff2da121790ab7e7b9247583e3a7eed2db5bd4dabc680303b1608f37dfdc836d96a704c03283bc05b4f6c5eb8"; BCRYPT_ALG_HANDLE alg; BCRYPT_HASH_HANDLE hash; - UCHAR buf[512], sha384[48]; + UCHAR buf[512], buf_hmac[1024], sha384[48], sha384_hmac[48]; ULONG size, len; char str[97]; NTSTATUS ret; @@ -337,6 +400,35 @@ static void test_sha384(void) ret = BCryptCloseAlgorithmProvider(alg, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + alg = NULL; + ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA384_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(alg != NULL, "alg not set\n"); + + hash = NULL; + len = sizeof(buf_hmac); + ret = BCryptCreateHash(alg, &hash, buf_hmac, len, (UCHAR *)"key", sizeof("key"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(hash != NULL, "hash not set\n"); + + ret = BCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + test_hash_length(hash, 48); + test_alg_name(hash, "SHA384"); + + memset(sha384_hmac, 0, sizeof(sha384_hmac)); + ret = BCryptFinishHash(hash, sha384_hmac, sizeof(sha384_hmac), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + format_hash( sha384_hmac, sizeof(sha384_hmac), str ); + ok(!strcmp(str, expected_hmac), "got %s\n", str); + + ret = BCryptDestroyHash(hash); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + ret = BCryptCloseAlgorithmProvider(alg, 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); } static void test_sha512(void) @@ -344,9 +436,12 @@ static void test_sha512(void) static const char expected[] = "d55ced17163bf5386f2cd9ff21d6fd7fe576a915065c24744d09cfae4ec84ee1e" "f6ef11bfbc5acce3639bab725b50a1fe2c204f8c820d6d7db0df0ecbc49c5ca"; + static const char expected_hmac[] = + "415fb6b10018ca03b38a1b1399c42ac0be5e8aceddb9a73103f5e543bf2d888f2" + "eecf91373941f9315dd730a77937fa92444450fbece86f409d9cb5ec48c6513"; BCRYPT_ALG_HANDLE alg; BCRYPT_HASH_HANDLE hash; - UCHAR buf[512], sha512[64]; + UCHAR buf[512], buf_hmac[1024], sha512[64], sha512_hmac[64]; ULONG size, len; char str[129]; NTSTATUS ret; @@ -414,15 +509,47 @@ static void test_sha512(void) ret = BCryptCloseAlgorithmProvider(alg, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + alg = NULL; + ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA512_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(alg != NULL, "alg not set\n"); + + hash = NULL; + len = sizeof(buf_hmac); + ret = BCryptCreateHash(alg, &hash, buf_hmac, len, (UCHAR *)"key", sizeof("key"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(hash != NULL, "hash not set\n"); + + ret = BCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + test_hash_length(hash, 64); + test_alg_name(hash, "SHA512"); + + memset(sha512_hmac, 0, sizeof(sha512_hmac)); + ret = BCryptFinishHash(hash, sha512_hmac, sizeof(sha512_hmac), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + format_hash( sha512_hmac, sizeof(sha512_hmac), str ); + ok(!strcmp(str, expected_hmac), "got %s\n", str); + + ret = BCryptDestroyHash(hash); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + ret = BCryptCloseAlgorithmProvider(alg, 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + } static void test_md5(void) { static const char expected[] = "e2a3e68d23ce348b8f68b3079de3d4c9"; + static const char expected_hmac[] = + "7bda029b93fa8d817fcc9e13d6bdf092"; BCRYPT_ALG_HANDLE alg; BCRYPT_HASH_HANDLE hash; - UCHAR buf[512], md5[16]; + UCHAR buf[512], buf_hmac[1024], md5[16], md5_hmac[16]; ULONG size, len; char str[65]; NTSTATUS ret; @@ -490,6 +617,35 @@ static void test_md5(void) ret = BCryptCloseAlgorithmProvider(alg, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + alg = NULL; + ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_MD5_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(alg != NULL, "alg not set\n"); + + hash = NULL; + len = sizeof(buf_hmac); + ret = BCryptCreateHash(alg, &hash, buf_hmac, len, (UCHAR *)"key", sizeof("key"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + ok(hash != NULL, "hash not set\n"); + + ret = BCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + test_hash_length(hash, 16); + test_alg_name(hash, "MD5"); + + memset(md5_hmac, 0, sizeof(md5_hmac)); + ret = BCryptFinishHash(hash, md5_hmac, sizeof(md5_hmac), 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + format_hash( md5_hmac, sizeof(md5_hmac), str ); + ok(!strcmp(str, expected_hmac), "got %s\n", str); + + ret = BCryptDestroyHash(hash); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + + ret = BCryptCloseAlgorithmProvider(alg, 0); + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); } START_TEST(bcrypt) diff --git a/include/bcrypt.h b/include/bcrypt.h index 3cd14d2d4e1..ddfd66e9646 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -82,6 +82,7 @@ typedef PVOID BCRYPT_HASH_HANDLE; #define BCRYPT_RNG_USE_ENTROPY_IN_BUFFER 0x00000001 #define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 +#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008 NTSTATUS WINAPI BCryptCloseAlgorithmProvider(BCRYPT_ALG_HANDLE, ULONG); NTSTATUS WINAPI BCryptCreateHash(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDLE *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG);