bcrypt: Implement BCRYPT_HASH_REUSABLE_FLAG.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
89f124ffc5
commit
98ea906b96
|
@ -366,13 +366,17 @@ static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define HASH_FLAG_HMAC 0x01
|
||||
#define HASH_FLAG_REUSABLE 0x02
|
||||
struct hash
|
||||
{
|
||||
struct object hdr;
|
||||
enum alg_id alg_id;
|
||||
BOOL hmac;
|
||||
struct hash_impl outer;
|
||||
struct hash_impl inner;
|
||||
struct object hdr;
|
||||
enum alg_id alg_id;
|
||||
ULONG flags;
|
||||
UCHAR *secret;
|
||||
ULONG secret_len;
|
||||
struct hash_impl outer;
|
||||
struct hash_impl inner;
|
||||
};
|
||||
|
||||
#define BLOCK_LENGTH_AES 16
|
||||
|
@ -587,19 +591,45 @@ NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *bu
|
|||
}
|
||||
}
|
||||
|
||||
static NTSTATUS prepare_hash( struct hash *hash )
|
||||
{
|
||||
UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
|
||||
int block_bytes, i;
|
||||
NTSTATUS status;
|
||||
|
||||
/* initialize hash */
|
||||
if ((status = hash_init( &hash->inner, hash->alg_id ))) return status;
|
||||
if (!(hash->flags & HASH_FLAG_HMAC)) return STATUS_SUCCESS;
|
||||
|
||||
/* initialize hmac */
|
||||
if ((status = hash_init( &hash->outer, hash->alg_id ))) return status;
|
||||
block_bytes = alg_props[hash->alg_id].block_bits / 8;
|
||||
if (hash->secret_len > block_bytes)
|
||||
{
|
||||
struct hash_impl temp;
|
||||
if ((status = hash_init( &temp, hash->alg_id ))) return status;
|
||||
if ((status = hash_update( &temp, hash->alg_id, hash->secret, hash->secret_len ))) return status;
|
||||
if ((status = hash_finish( &temp, hash->alg_id, buffer,
|
||||
alg_props[hash->alg_id].hash_length ))) return status;
|
||||
}
|
||||
else memcpy( buffer, hash->secret, hash->secret_len );
|
||||
|
||||
for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
|
||||
if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) return status;
|
||||
for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
|
||||
return hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
|
||||
UCHAR *secret, ULONG secretlen, ULONG flags )
|
||||
{
|
||||
struct algorithm *alg = algorithm;
|
||||
UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
|
||||
struct hash *hash;
|
||||
int block_bytes;
|
||||
NTSTATUS status;
|
||||
int i;
|
||||
|
||||
TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
|
||||
secret, secretlen, flags );
|
||||
if (flags)
|
||||
if (flags & ~BCRYPT_HASH_REUSABLE_FLAG)
|
||||
{
|
||||
FIXME( "unimplemented flags %08x\n", flags );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
@ -608,38 +638,23 @@ NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDL
|
|||
if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
|
||||
if (object) FIXME( "ignoring object buffer\n" );
|
||||
|
||||
if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
|
||||
if (!(hash = heap_alloc_zero( sizeof(*hash) ))) return STATUS_NO_MEMORY;
|
||||
hash->hdr.magic = MAGIC_HASH;
|
||||
hash->alg_id = alg->id;
|
||||
hash->hmac = alg->hmac;
|
||||
if (alg->hmac) hash->flags = HASH_FLAG_HMAC;
|
||||
if (flags & BCRYPT_HASH_REUSABLE_FLAG) hash->flags |= HASH_FLAG_REUSABLE;
|
||||
|
||||
/* initialize hash */
|
||||
if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
|
||||
if (!hash->hmac) goto end;
|
||||
|
||||
/* initialize hmac */
|
||||
if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
|
||||
block_bytes = alg_props[hash->alg_id].block_bits / 8;
|
||||
if (secretlen > block_bytes)
|
||||
if (secretlen && !(hash->secret = heap_alloc( secretlen )))
|
||||
{
|
||||
struct hash_impl temp;
|
||||
if ((status = hash_init( &temp, hash->alg_id ))) goto end;
|
||||
if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
|
||||
if ((status = hash_finish( &temp, hash->alg_id, buffer,
|
||||
alg_props[hash->alg_id].hash_length ))) goto end;
|
||||
heap_free( hash );
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( buffer, secret, secretlen );
|
||||
}
|
||||
for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
|
||||
if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
|
||||
for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
|
||||
status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
|
||||
memcpy( hash->secret, secret, secretlen );
|
||||
hash->secret_len = secretlen;
|
||||
|
||||
end:
|
||||
if (status != STATUS_SUCCESS)
|
||||
if ((status = prepare_hash( hash )) != STATUS_SUCCESS)
|
||||
{
|
||||
heap_free( hash->secret );
|
||||
heap_free( hash );
|
||||
return status;
|
||||
}
|
||||
|
@ -664,6 +679,12 @@ NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HAND
|
|||
return STATUS_NO_MEMORY;
|
||||
|
||||
memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
|
||||
if (hash_orig->secret && !(hash_copy->secret = heap_alloc( hash_orig->secret_len )))
|
||||
{
|
||||
heap_free( hash_copy );
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy( hash_copy->secret, hash_orig->secret, hash_orig->secret_len );
|
||||
|
||||
*handle_copy = hash_copy;
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -677,6 +698,7 @@ NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
|
|||
|
||||
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_PARAMETER;
|
||||
hash->hdr.magic = 0;
|
||||
heap_free( hash->secret );
|
||||
heap_free( hash );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -705,13 +727,19 @@ 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;
|
||||
|
||||
if (!hash->hmac)
|
||||
return hash_finish( &hash->inner, hash->alg_id, output, size );
|
||||
if (!(hash->flags & HASH_FLAG_HMAC))
|
||||
{
|
||||
if ((status = hash_finish( &hash->inner, hash->alg_id, output, size ))) return status;
|
||||
if (hash->flags & HASH_FLAG_REUSABLE) return prepare_hash( hash );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
hash_length = alg_props[hash->alg_id].hash_length;
|
||||
if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
|
||||
if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
|
||||
return hash_finish( &hash->outer, hash->alg_id, output, size );
|
||||
if ((status = hash_finish( &hash->outer, hash->alg_id, output, size ))) return status;
|
||||
if (hash->flags & HASH_FLAG_REUSABLE) return prepare_hash( hash );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
|
||||
|
|
|
@ -221,7 +221,9 @@ struct hash_test
|
|||
const char *alg;
|
||||
unsigned hash_size;
|
||||
const char *hash;
|
||||
const char *hash2;
|
||||
const char *hmac_hash;
|
||||
const char *hmac_hash2;
|
||||
};
|
||||
|
||||
static void test_hash(const struct hash_test *test)
|
||||
|
@ -269,6 +271,35 @@ static void test_hash(const struct hash_test *test)
|
|||
ret = pBCryptDestroyHash(hash);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
hash = NULL;
|
||||
len = sizeof(buf);
|
||||
ret = pBCryptCreateHash(alg, &hash, buf, len, NULL, 0, BCRYPT_HASH_REUSABLE_FLAG);
|
||||
ok(ret == STATUS_SUCCESS || broken(ret == STATUS_INVALID_PARAMETER) /* < win8 */, "got %08x\n", ret);
|
||||
if (ret == STATUS_SUCCESS)
|
||||
{
|
||||
ret = pBCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
memset(hash_buf, 0, sizeof(hash_buf));
|
||||
ret = pBCryptFinishHash(hash, hash_buf, test->hash_size, 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
format_hash( hash_buf, test->hash_size, str );
|
||||
ok(!strcmp(str, test->hash), "got %s\n", str);
|
||||
|
||||
/* reuse it */
|
||||
ret = pBCryptHashData(hash, (UCHAR *)"tset", sizeof("tset"), 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
memset(hash_buf, 0, sizeof(hash_buf));
|
||||
ret = pBCryptFinishHash(hash, hash_buf, test->hash_size, 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
format_hash( hash_buf, test->hash_size, str );
|
||||
ok(!strcmp(str, test->hash2), "got %s\n", str);
|
||||
|
||||
ret = pBCryptDestroyHash(hash);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
}
|
||||
|
||||
ret = pBCryptCloseAlgorithmProvider(alg, 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
|
@ -298,6 +329,35 @@ static void test_hash(const struct hash_test *test)
|
|||
ret = pBCryptDestroyHash(hash);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
hash = NULL;
|
||||
len = sizeof(buf_hmac);
|
||||
ret = pBCryptCreateHash(alg, &hash, buf_hmac, len, (UCHAR *)"key", sizeof("key"), BCRYPT_HASH_REUSABLE_FLAG);
|
||||
ok(ret == STATUS_SUCCESS || broken(ret == STATUS_INVALID_PARAMETER) /* < win8 */, "got %08x\n", ret);
|
||||
if (ret == STATUS_SUCCESS)
|
||||
{
|
||||
ret = pBCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
memset(hmac_hash, 0, sizeof(hmac_hash));
|
||||
ret = pBCryptFinishHash(hash, hmac_hash, test->hash_size, 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
format_hash( hmac_hash, test->hash_size, str );
|
||||
ok(!strcmp(str, test->hmac_hash), "got %s\n", str);
|
||||
|
||||
/* reuse it */
|
||||
ret = pBCryptHashData(hash, (UCHAR *)"tset", sizeof("tset"), 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
|
||||
memset(hmac_hash, 0, sizeof(hmac_hash));
|
||||
ret = pBCryptFinishHash(hash, hmac_hash, test->hash_size, 0);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
format_hash( hmac_hash, test->hash_size, str );
|
||||
ok(!strcmp(str, test->hmac_hash2), "got %s\n", str);
|
||||
|
||||
ret = pBCryptDestroyHash(hash);
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
}
|
||||
|
||||
ret = pBCryptDestroyHash(hash);
|
||||
ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret);
|
||||
|
||||
|
@ -310,52 +370,57 @@ static void test_hash(const struct hash_test *test)
|
|||
|
||||
static void test_hashes(void)
|
||||
{
|
||||
static const struct hash_test tests[] = {
|
||||
{
|
||||
"SHA1",
|
||||
20,
|
||||
"961fa64958818f767707072755d7018dcd278e94",
|
||||
"2472cf65d0e090618d769d3e46f0d9446cf212da"
|
||||
static const struct hash_test tests[] =
|
||||
{
|
||||
{ "SHA1", 20,
|
||||
"961fa64958818f767707072755d7018dcd278e94",
|
||||
"9314f62ff64197143c91fc86de37e9ae776a3fb8",
|
||||
"2472cf65d0e090618d769d3e46f0d9446cf212da",
|
||||
"b2d2ba8cfd714d474cf0d9622cc5d15e1f53d53f",
|
||||
},
|
||||
{
|
||||
"SHA256",
|
||||
32,
|
||||
"ceb73749c899693706ede1e30c9929b3fd5dd926163831c2fb8bd41e6efb1126",
|
||||
"34c1aa473a4468a91d06e7cdbc75bc4f93b830ccfc2a47ffd74e8e6ed29e4c72"
|
||||
{ "SHA256", 32,
|
||||
"ceb73749c899693706ede1e30c9929b3fd5dd926163831c2fb8bd41e6efb1126",
|
||||
"ea0938c118a7b15954f41b85195f2b42aec3a9429c63f593cfa65c137ffaa986",
|
||||
"34c1aa473a4468a91d06e7cdbc75bc4f93b830ccfc2a47ffd74e8e6ed29e4c72",
|
||||
"55feb7052060bd99e33f36eb0982c7f4856eb6a84fbefe19a1afd9faafc3af6f",
|
||||
},
|
||||
{
|
||||
"SHA384",
|
||||
48,
|
||||
"62b21e90c9022b101671ba1f808f8631a8149f0f12904055839a35c1ca78ae53"
|
||||
"63eed1e743a692d70e0504b0cfd12ef9",
|
||||
"4b3e6d6ff2da121790ab7e7b9247583e3a7eed2db5bd4dabc680303b1608f37d"
|
||||
"fdc836d96a704c03283bc05b4f6c5eb8"
|
||||
{ "SHA384", 48,
|
||||
"62b21e90c9022b101671ba1f808f8631a8149f0f12904055839a35c1ca78ae53"
|
||||
"63eed1e743a692d70e0504b0cfd12ef9",
|
||||
"724db7c0bbc51ef1ac3fc793083fc54c0e5c423faec9b11378c01c236b19aaaf"
|
||||
"a45177ad055feaf003968cc40ece44c7",
|
||||
"4b3e6d6ff2da121790ab7e7b9247583e3a7eed2db5bd4dabc680303b1608f37d"
|
||||
"fdc836d96a704c03283bc05b4f6c5eb8",
|
||||
"03e1818e5c165a0e54619e513acb06c393e1a6cb0ddbb4036b5f29617b334642"
|
||||
"e6e0be8b214d8508595b17a8c4b4e7db",
|
||||
},
|
||||
{
|
||||
"SHA512",
|
||||
64,
|
||||
"d55ced17163bf5386f2cd9ff21d6fd7fe576a915065c24744d09cfae4ec84ee1"
|
||||
"ef6ef11bfbc5acce3639bab725b50a1fe2c204f8c820d6d7db0df0ecbc49c5ca",
|
||||
"415fb6b10018ca03b38a1b1399c42ac0be5e8aceddb9a73103f5e543bf2d888f"
|
||||
"2eecf91373941f9315dd730a77937fa92444450fbece86f409d9cb5ec48c6513"
|
||||
{ "SHA512", 64,
|
||||
"d55ced17163bf5386f2cd9ff21d6fd7fe576a915065c24744d09cfae4ec84ee1"
|
||||
"ef6ef11bfbc5acce3639bab725b50a1fe2c204f8c820d6d7db0df0ecbc49c5ca",
|
||||
"7752d707b54d2b00e7d1c09120d189475b0fd2e31ebb988cf0a01fc8492ddc0b"
|
||||
"3ca9c9ca61d9d7d1fb65ca7665e87f043c1d5bc9f786f8345e951c2d91ac594f",
|
||||
"415fb6b10018ca03b38a1b1399c42ac0be5e8aceddb9a73103f5e543bf2d888f"
|
||||
"2eecf91373941f9315dd730a77937fa92444450fbece86f409d9cb5ec48c6513",
|
||||
"1487bcecba46ae677622fa499e4cb2f0fdf92f6f3427cba76382d537a06e49c3"
|
||||
"3e70a2fc1fc730092bf21128c3704cc6387f6dfbf7e2f9f315bbb894505a1205",
|
||||
},
|
||||
{
|
||||
"MD2",
|
||||
16,
|
||||
"1bb33606ba908912a84221109d29cd7e",
|
||||
"7f05b0638d77f4a27f3a9c4d353cd648"
|
||||
{ "MD2", 16,
|
||||
"1bb33606ba908912a84221109d29cd7e",
|
||||
"b9a6ad9323b17e2d0cd389dddd6ef78a",
|
||||
"7f05b0638d77f4a27f3a9c4d353cd648",
|
||||
"05980873e6bfdd05dd7b30078de7e42a",
|
||||
},
|
||||
{
|
||||
"MD4",
|
||||
16,
|
||||
"74b5db93c0b41e36ca7074338fc0b637",
|
||||
"bc2e8ac4d8248ed21b8d26227a30ea3a"
|
||||
{ "MD4", 16,
|
||||
"74b5db93c0b41e36ca7074338fc0b637",
|
||||
"a14a9ff2059a8c28f47b01e6bc48a1bf",
|
||||
"bc2e8ac4d8248ed21b8d26227a30ea3a",
|
||||
"b609db0eb4b8669db74f2c20099701e4",
|
||||
},
|
||||
{
|
||||
"MD5",
|
||||
16,
|
||||
"e2a3e68d23ce348b8f68b3079de3d4c9",
|
||||
"7bda029b93fa8d817fcc9e13d6bdf092"
|
||||
{ "MD5", 16,
|
||||
"e2a3e68d23ce348b8f68b3079de3d4c9",
|
||||
"bcdd7ca574342aa9db0e212348eacb16",
|
||||
"7bda029b93fa8d817fcc9e13d6bdf092",
|
||||
"dd636ab8e9592c5088e57c37d44c5bb3",
|
||||
}
|
||||
};
|
||||
unsigned i;
|
||||
|
|
|
@ -222,6 +222,9 @@ typedef PVOID BCRYPT_HASH_HANDLE;
|
|||
/* Flags for BCryptEncrypt/BCryptDecrypt */
|
||||
#define BCRYPT_BLOCK_PADDING 0x00000001
|
||||
|
||||
/* Flags for BCryptCreateHash */
|
||||
#define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue