bcrypt: Use internal helpers to generate hashes.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c650ec93ef
commit
a6e589bc52
|
@ -666,7 +666,7 @@ NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *bu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS prepare_hash( struct hash *hash )
|
static NTSTATUS hash_prepare( struct hash *hash )
|
||||||
{
|
{
|
||||||
UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
|
UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
|
||||||
int block_bytes, i;
|
int block_bytes, i;
|
||||||
|
@ -695,15 +695,47 @@ static NTSTATUS prepare_hash( struct hash *hash )
|
||||||
return hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
|
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,
|
static NTSTATUS hash_create( const struct algorithm *alg, UCHAR *secret, ULONG secret_len, ULONG flags,
|
||||||
UCHAR *secret, ULONG secretlen, ULONG flags )
|
struct hash **ret_hash )
|
||||||
|
{
|
||||||
|
struct hash *hash;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if (!(hash = heap_alloc_zero( sizeof(*hash) ))) return STATUS_NO_MEMORY;
|
||||||
|
hash->hdr.magic = MAGIC_HASH;
|
||||||
|
hash->alg_id = alg->id;
|
||||||
|
if (alg->flags & BCRYPT_ALG_HANDLE_HMAC_FLAG) hash->flags = HASH_FLAG_HMAC;
|
||||||
|
if ((alg->flags & BCRYPT_HASH_REUSABLE_FLAG) || (flags & BCRYPT_HASH_REUSABLE_FLAG))
|
||||||
|
hash->flags |= HASH_FLAG_REUSABLE;
|
||||||
|
|
||||||
|
if (secret_len && !(hash->secret = heap_alloc( secret_len )))
|
||||||
|
{
|
||||||
|
heap_free( hash );
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
memcpy( hash->secret, secret, secret_len );
|
||||||
|
hash->secret_len = secret_len;
|
||||||
|
|
||||||
|
if ((status = hash_prepare( hash )))
|
||||||
|
{
|
||||||
|
heap_free( hash->secret );
|
||||||
|
heap_free( hash );
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret_hash = hash;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object,
|
||||||
|
ULONG object_len, UCHAR *secret, ULONG secret_len, ULONG flags )
|
||||||
{
|
{
|
||||||
struct algorithm *alg = algorithm;
|
struct algorithm *alg = algorithm;
|
||||||
struct hash *hash;
|
struct hash *hash;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
|
TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, object_len,
|
||||||
secret, secretlen, flags );
|
secret, secret_len, flags );
|
||||||
if (flags & ~BCRYPT_HASH_REUSABLE_FLAG)
|
if (flags & ~BCRYPT_HASH_REUSABLE_FLAG)
|
||||||
{
|
{
|
||||||
FIXME( "unimplemented flags %08x\n", flags );
|
FIXME( "unimplemented flags %08x\n", flags );
|
||||||
|
@ -713,28 +745,7 @@ NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDL
|
||||||
if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
|
if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
|
||||||
if (object) FIXME( "ignoring object buffer\n" );
|
if (object) FIXME( "ignoring object buffer\n" );
|
||||||
|
|
||||||
if (!(hash = heap_alloc_zero( sizeof(*hash) ))) return STATUS_NO_MEMORY;
|
if ((status = hash_create( alg, secret, secret_len, flags, &hash ))) return status;
|
||||||
hash->hdr.magic = MAGIC_HASH;
|
|
||||||
hash->alg_id = alg->id;
|
|
||||||
if (alg->flags & BCRYPT_ALG_HANDLE_HMAC_FLAG) hash->flags = HASH_FLAG_HMAC;
|
|
||||||
if ((alg->flags & BCRYPT_HASH_REUSABLE_FLAG) || (flags & BCRYPT_HASH_REUSABLE_FLAG))
|
|
||||||
hash->flags |= HASH_FLAG_REUSABLE;
|
|
||||||
|
|
||||||
if (secretlen && !(hash->secret = heap_alloc( secretlen )))
|
|
||||||
{
|
|
||||||
heap_free( hash );
|
|
||||||
return STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
memcpy( hash->secret, secret, secretlen );
|
|
||||||
hash->secret_len = secretlen;
|
|
||||||
|
|
||||||
if ((status = prepare_hash( hash )) != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
heap_free( hash->secret );
|
|
||||||
heap_free( hash );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
*handle = hash;
|
*handle = hash;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -766,6 +777,14 @@ NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HAND
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hash_destroy( struct hash *hash )
|
||||||
|
{
|
||||||
|
if (!hash) return;
|
||||||
|
hash->hdr.magic = 0;
|
||||||
|
heap_free( hash->secret );
|
||||||
|
heap_free( hash );
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
|
NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
|
||||||
{
|
{
|
||||||
struct hash *hash = handle;
|
struct hash *hash = handle;
|
||||||
|
@ -773,9 +792,7 @@ NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
|
||||||
TRACE( "%p\n", handle );
|
TRACE( "%p\n", handle );
|
||||||
|
|
||||||
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_PARAMETER;
|
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_PARAMETER;
|
||||||
hash->hdr.magic = 0;
|
hash_destroy( hash );
|
||||||
heap_free( hash->secret );
|
|
||||||
heap_free( hash );
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,22 +808,16 @@ NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG s
|
||||||
return hash_update( &hash->inner, hash->alg_id, input, size );
|
return hash_update( &hash->inner, hash->alg_id, input, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
|
static NTSTATUS hash_finalize( struct hash *hash, UCHAR *output, ULONG size )
|
||||||
{
|
{
|
||||||
UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
|
UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
|
||||||
struct hash *hash = handle;
|
|
||||||
NTSTATUS status;
|
|
||||||
int hash_length;
|
int hash_length;
|
||||||
|
NTSTATUS status;
|
||||||
TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
|
|
||||||
|
|
||||||
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
|
|
||||||
if (!output) return STATUS_INVALID_PARAMETER;
|
|
||||||
|
|
||||||
if (!(hash->flags & HASH_FLAG_HMAC))
|
if (!(hash->flags & HASH_FLAG_HMAC))
|
||||||
{
|
{
|
||||||
if ((status = hash_finish( &hash->inner, hash->alg_id, output, size ))) return status;
|
if ((status = hash_finish( &hash->inner, hash->alg_id, output, size ))) return status;
|
||||||
if (hash->flags & HASH_FLAG_REUSABLE) return prepare_hash( hash );
|
if (hash->flags & HASH_FLAG_REUSABLE) return hash_prepare( hash );
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,40 +825,43 @@ NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULON
|
||||||
if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
|
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;
|
if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
|
||||||
if ((status = hash_finish( &hash->outer, hash->alg_id, output, size ))) return status;
|
if ((status = hash_finish( &hash->outer, hash->alg_id, output, size ))) return status;
|
||||||
if (hash->flags & HASH_FLAG_REUSABLE) return prepare_hash( hash );
|
|
||||||
|
if (hash->flags & HASH_FLAG_REUSABLE) return hash_prepare( hash );
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
|
NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
|
||||||
UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
|
|
||||||
{
|
{
|
||||||
|
struct hash *hash = handle;
|
||||||
|
|
||||||
|
TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
|
||||||
|
|
||||||
|
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
|
||||||
|
if (!output) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
return hash_finalize( hash, output, size );
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secret_len,
|
||||||
|
UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len )
|
||||||
|
{
|
||||||
|
struct algorithm *alg = algorithm;
|
||||||
|
struct hash *hash;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
BCRYPT_HASH_HANDLE handle;
|
|
||||||
|
|
||||||
TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
|
TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secret_len, input, input_len, output, output_len );
|
||||||
input, inputlen, output, outputlen );
|
|
||||||
|
|
||||||
status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
|
if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
|
if ((status = hash_create( alg, secret, secret_len, 0, &hash ))) return status;
|
||||||
|
if ((status = hash_update( &hash->inner, hash->alg_id, input, input_len )))
|
||||||
{
|
{
|
||||||
|
hash_destroy( hash );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
status = hash_finalize( hash, output, output_len );
|
||||||
status = BCryptHashData( handle, input, inputlen, 0 );
|
hash_destroy( hash );
|
||||||
if (status != STATUS_SUCCESS)
|
return status;
|
||||||
{
|
|
||||||
BCryptDestroyHash( handle );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = BCryptFinishHash( handle, output, outputlen, 0 );
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
BCryptDestroyHash( handle );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BCryptDestroyHash( handle );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS key_asymmetric_create( struct key **ret_key, struct algorithm *alg, ULONG bitlen,
|
static NTSTATUS key_asymmetric_create( struct key **ret_key, struct algorithm *alg, ULONG bitlen,
|
||||||
|
@ -1685,7 +1699,7 @@ NTSTATUS WINAPI BCryptDeriveKeyCapi( BCRYPT_HASH_HANDLE handle, BCRYPT_ALG_HANDL
|
||||||
}
|
}
|
||||||
|
|
||||||
len = builtin_algorithms[hash->alg_id].hash_length;
|
len = builtin_algorithms[hash->alg_id].hash_length;
|
||||||
if ((status = BCryptFinishHash( handle, buf, len, 0 ))) return status;
|
if ((status = hash_finalize( hash, buf, len ))) return status;
|
||||||
|
|
||||||
if (len < keylen)
|
if (len < keylen)
|
||||||
{
|
{
|
||||||
|
@ -1698,20 +1712,20 @@ NTSTATUS WINAPI BCryptDeriveKeyCapi( BCRYPT_HASH_HANDLE handle, BCRYPT_ALG_HANDL
|
||||||
pad2[i] = 0x5c ^ (i < len ? buf[i] : 0);
|
pad2[i] = 0x5c ^ (i < len ? buf[i] : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status = prepare_hash( hash )) ||
|
if ((status = hash_prepare( hash )) ||
|
||||||
(status = BCryptHashData( handle, pad1, sizeof(pad1), 0 )) ||
|
(status = hash_update( &hash->inner, hash->alg_id, pad1, sizeof(pad1) )) ||
|
||||||
(status = BCryptFinishHash( handle, buf, len, 0 ))) return status;
|
(status = hash_finalize( hash, buf, len ))) return status;
|
||||||
|
|
||||||
if ((status = prepare_hash( hash )) ||
|
if ((status = hash_prepare( hash )) ||
|
||||||
(status = BCryptHashData( handle, pad2, sizeof(pad2), 0 )) ||
|
(status = hash_update( &hash->inner, hash->alg_id, pad2, sizeof(pad2) )) ||
|
||||||
(status = BCryptFinishHash( handle, buf + len, len, 0 ))) return status;
|
(status = hash_finalize( hash, buf + len, len ))) return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy( key, buf, keylen );
|
memcpy( key, buf, keylen );
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS pbkdf2( BCRYPT_HASH_HANDLE handle, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len,
|
static NTSTATUS pbkdf2( struct hash *hash, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len,
|
||||||
ULONGLONG iterations, ULONG i, UCHAR *dst, ULONG hash_len )
|
ULONGLONG iterations, ULONG i, UCHAR *dst, ULONG hash_len )
|
||||||
{
|
{
|
||||||
NTSTATUS status = STATUS_INVALID_PARAMETER;
|
NTSTATUS status = STATUS_INVALID_PARAMETER;
|
||||||
|
@ -1725,8 +1739,7 @@ static NTSTATUS pbkdf2( BCRYPT_HASH_HANDLE handle, UCHAR *pwd, ULONG pwd_len, UC
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
{
|
{
|
||||||
/* use salt || INT(i) */
|
/* use salt || INT(i) */
|
||||||
status = BCryptHashData( handle, salt, salt_len, 0 );
|
if ((status = hash_update( &hash->inner, hash->alg_id, salt, salt_len )))
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
heap_free( buf );
|
heap_free( buf );
|
||||||
return status;
|
return status;
|
||||||
|
@ -1735,17 +1748,17 @@ static NTSTATUS pbkdf2( BCRYPT_HASH_HANDLE handle, UCHAR *pwd, ULONG pwd_len, UC
|
||||||
bytes[1] = (i >> 16) & 0xff;
|
bytes[1] = (i >> 16) & 0xff;
|
||||||
bytes[2] = (i >> 8) & 0xff;
|
bytes[2] = (i >> 8) & 0xff;
|
||||||
bytes[3] = i & 0xff;
|
bytes[3] = i & 0xff;
|
||||||
status = BCryptHashData( handle, bytes, 4, 0 );
|
status = hash_update( &hash->inner, hash->alg_id, bytes, 4 );
|
||||||
}
|
}
|
||||||
else status = BCryptHashData( handle, buf, hash_len, 0 ); /* use U_j */
|
else status = hash_update( &hash->inner, hash->alg_id, buf, hash_len ); /* use U_j */
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
|
if (status)
|
||||||
{
|
{
|
||||||
heap_free( buf );
|
heap_free( buf );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = BCryptFinishHash( handle, buf, hash_len, 0 );
|
if ((status = hash_finalize( hash, buf, hash_len )))
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
heap_free( buf );
|
heap_free( buf );
|
||||||
return status;
|
return status;
|
||||||
|
@ -1764,7 +1777,7 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO
|
||||||
{
|
{
|
||||||
struct algorithm *alg = handle;
|
struct algorithm *alg = handle;
|
||||||
ULONG hash_len, block_count, bytes_left, i;
|
ULONG hash_len, block_count, bytes_left, i;
|
||||||
BCRYPT_HASH_HANDLE hash;
|
struct hash *hash;
|
||||||
UCHAR *partial;
|
UCHAR *partial;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
|
@ -1779,17 +1792,14 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO
|
||||||
block_count = 1 + ((dk_len - 1) / hash_len); /* ceil(dk_len / hash_len) */
|
block_count = 1 + ((dk_len - 1) / hash_len); /* ceil(dk_len / hash_len) */
|
||||||
bytes_left = dk_len - (block_count - 1) * hash_len;
|
bytes_left = dk_len - (block_count - 1) * hash_len;
|
||||||
|
|
||||||
status = BCryptCreateHash( handle, &hash, NULL, 0, pwd, pwd_len, BCRYPT_HASH_REUSABLE_FLAG );
|
if ((status = hash_create( alg, pwd, pwd_len, BCRYPT_HASH_REUSABLE_FLAG, &hash ))) return status;
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
/* full blocks */
|
/* full blocks */
|
||||||
for (i = 1; i < block_count; i++)
|
for (i = 1; i < block_count; i++)
|
||||||
{
|
{
|
||||||
status = pbkdf2( hash, pwd, pwd_len, salt, salt_len, iterations, i, dk + ((i - 1) * hash_len), hash_len );
|
if ((status = pbkdf2( hash, pwd, pwd_len, salt, salt_len, iterations, i, dk + ((i - 1) * hash_len), hash_len )))
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
BCryptDestroyHash( hash );
|
hash_destroy( hash );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1797,20 +1807,19 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO
|
||||||
/* final partial block */
|
/* final partial block */
|
||||||
if (!(partial = heap_alloc( hash_len )))
|
if (!(partial = heap_alloc( hash_len )))
|
||||||
{
|
{
|
||||||
BCryptDestroyHash( hash );
|
hash_destroy( hash );
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pbkdf2( hash, pwd, pwd_len, salt, salt_len, iterations, block_count, partial, hash_len );
|
if ((status = pbkdf2( hash, pwd, pwd_len, salt, salt_len, iterations, block_count, partial, hash_len )))
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
BCryptDestroyHash( hash );
|
hash_destroy( hash );
|
||||||
heap_free( partial );
|
heap_free( partial );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
memcpy( dk + ((block_count - 1) * hash_len), partial, bytes_left );
|
memcpy( dk + ((block_count - 1) * hash_len), partial, bytes_left );
|
||||||
|
|
||||||
BCryptDestroyHash( hash );
|
hash_destroy( hash );
|
||||||
heap_free( partial );
|
heap_free( partial );
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue