mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
470 lines
13 KiB
Diff
470 lines
13 KiB
Diff
|
From f527689b793100c79654ac5d6c1376d128ca3175 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||
|
Date: Mon, 19 Dec 2016 23:58:52 +0100
|
||
|
Subject: bcrypt: Directly implement hmac computation.
|
||
|
|
||
|
---
|
||
|
dlls/bcrypt/bcrypt_main.c | 277 +++++++++++++++++-----------------------------
|
||
|
1 file changed, 104 insertions(+), 173 deletions(-)
|
||
|
|
||
|
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
|
||
|
index 937bdf7..af2314a 100644
|
||
|
--- a/dlls/bcrypt/bcrypt_main.c
|
||
|
+++ b/dlls/bcrypt/bcrypt_main.c
|
||
|
@@ -60,9 +60,6 @@ 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
|
||
|
|
||
|
@@ -99,9 +96,6 @@ 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
|
||
|
|
||
|
@@ -163,6 +157,8 @@ enum alg_id
|
||
|
ALG_ID_SHA512
|
||
|
};
|
||
|
|
||
|
+#define MAX_HASH_OUTPUT_BYTES 64
|
||
|
+
|
||
|
static const struct {
|
||
|
ULONG hash_length;
|
||
|
const WCHAR *alg_name;
|
||
|
@@ -183,6 +179,19 @@ struct algorithm
|
||
|
BOOL hmac;
|
||
|
};
|
||
|
|
||
|
+#define MAX_HASH_BLOCK_BITS 1024
|
||
|
+
|
||
|
+int alg_block_bits[] =
|
||
|
+{
|
||
|
+ /* ALG_ID_AES */ 0,
|
||
|
+ /* ALG_ID_MD5 */ 512,
|
||
|
+ /* ALG_ID_RNG */ 0,
|
||
|
+ /* ALG_ID_SHA1 */ 512,
|
||
|
+ /* ALG_ID_SHA256 */ 512,
|
||
|
+ /* ALG_ID_SHA384 */ 1024,
|
||
|
+ /* ALG_ID_SHA512 */ 1024
|
||
|
+};
|
||
|
+
|
||
|
NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
|
||
|
{
|
||
|
const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
|
||
|
@@ -289,24 +298,20 @@ NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
|
||
|
}
|
||
|
|
||
|
#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
|
||
|
-struct hash
|
||
|
+struct hash_impl
|
||
|
{
|
||
|
- 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;
|
||
|
};
|
||
|
|
||
|
-static NTSTATUS hash_init( struct hash *hash )
|
||
|
+static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
|
||
|
{
|
||
|
- switch (hash->alg_id)
|
||
|
+ switch (alg_id)
|
||
|
{
|
||
|
case ALG_ID_MD5:
|
||
|
CC_MD5_Init( &hash->u.md5_ctx );
|
||
|
@@ -329,50 +334,16 @@ static NTSTATUS hash_init( struct hash *hash )
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- ERR( "unhandled id %u\n", hash->alg_id );
|
||
|
+ ERR( "unhandled id %u\n", alg_id );
|
||
|
return STATUS_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
-static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
|
||
|
+static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
|
||
|
+ UCHAR *input, ULONG 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)
|
||
|
+ switch (alg_id)
|
||
|
{
|
||
|
case ALG_ID_MD5:
|
||
|
CC_MD5_Update( &hash->u.md5_ctx, input, size );
|
||
|
@@ -395,21 +366,16 @@ static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- ERR( "unhandled id %u\n", hash->alg_id );
|
||
|
+ ERR( "unhandled id %u\n", alg_id );
|
||
|
return STATUS_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
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 )
|
||
|
+static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
|
||
|
+ UCHAR *output, ULONG size )
|
||
|
{
|
||
|
- switch (hash->alg_id)
|
||
|
+ switch (alg_id)
|
||
|
{
|
||
|
case ALG_ID_MD5:
|
||
|
CC_MD5_Final( output, &hash->u.md5_ctx );
|
||
|
@@ -432,37 +398,25 @@ static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- ERR( "unhandled id %u\n", hash->alg_id );
|
||
|
+ ERR( "unhandled id %u\n", alg_id );
|
||
|
break;
|
||
|
}
|
||
|
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 hash_impl
|
||
|
{
|
||
|
- struct object hdr;
|
||
|
- enum alg_id alg_id;
|
||
|
- BOOL hmac;
|
||
|
- union
|
||
|
- {
|
||
|
- gnutls_hash_hd_t hash_handle;
|
||
|
- gnutls_hmac_hd_t hmac_handle;
|
||
|
- } u;
|
||
|
+ gnutls_hash_hd_t hash_handle;
|
||
|
};
|
||
|
|
||
|
-static NTSTATUS hash_init( struct hash *hash )
|
||
|
+static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
|
||
|
{
|
||
|
gnutls_digest_algorithm_t alg;
|
||
|
|
||
|
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
|
||
|
|
||
|
- switch (hash->alg_id)
|
||
|
+ switch (alg_id)
|
||
|
{
|
||
|
case ALG_ID_MD5:
|
||
|
alg = GNUTLS_DIG_MD5;
|
||
|
@@ -484,117 +438,63 @@ static NTSTATUS hash_init( struct hash *hash )
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- ERR( "unhandled id %u\n", hash->alg_id );
|
||
|
- return STATUS_NOT_IMPLEMENTED;
|
||
|
- }
|
||
|
-
|
||
|
- 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 );
|
||
|
+ ERR( "unhandled id %u\n", 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->u.hash_handle, input, size )) return STATUS_INTERNAL_ERROR;
|
||
|
+ if (pgnutls_hash_init( &hash->hash_handle, alg )) return STATUS_INTERNAL_ERROR;
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
-static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
|
||
|
+static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
|
||
|
+ UCHAR *input, ULONG size )
|
||
|
{
|
||
|
- if (pgnutls_hmac( hash->u.hmac_handle, input, size )) return STATUS_INTERNAL_ERROR;
|
||
|
+ if (pgnutls_hash( hash->hash_handle, input, size )) return STATUS_INTERNAL_ERROR;
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
-static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
|
||
|
+static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
|
||
|
+ UCHAR *output, ULONG size )
|
||
|
{
|
||
|
- pgnutls_hash_deinit( hash->u.hash_handle, output );
|
||
|
+ pgnutls_hash_deinit( hash->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 hash_impl
|
||
|
{
|
||
|
- struct object hdr;
|
||
|
- BOOL hmac;
|
||
|
- enum alg_id alg_id;
|
||
|
-};
|
||
|
|
||
|
-static NTSTATUS hash_init( struct hash *hash )
|
||
|
-{
|
||
|
- ERR( "support for hashes not available at build time\n" );
|
||
|
- 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 )
|
||
|
+static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
|
||
|
{
|
||
|
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 )
|
||
|
+static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
|
||
|
+ 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 )
|
||
|
+static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
|
||
|
+ UCHAR *output, ULONG size )
|
||
|
{
|
||
|
ERR( "support for hashes not available at build time\n" );
|
||
|
return STATUS_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
-static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
|
||
|
+struct hash
|
||
|
{
|
||
|
- ERR( "support for hashes not available at build time\n" );
|
||
|
- return STATUS_NOT_IMPLEMENTED;
|
||
|
-}
|
||
|
-#endif
|
||
|
+ struct object hdr;
|
||
|
+ enum alg_id alg_id;
|
||
|
+ BOOL hmac;
|
||
|
+ struct hash_impl outer;
|
||
|
+ struct hash_impl inner;
|
||
|
+};
|
||
|
|
||
|
#ifdef _WIN64
|
||
|
#define OBJECT_LENGTH_AES 654
|
||
|
@@ -787,8 +687,11 @@ NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDL
|
||
|
UCHAR *secret, ULONG secretlen, ULONG flags )
|
||
|
{
|
||
|
struct algorithm *alg = algorithm;
|
||
|
+ UCHAR buffer[MAX_HASH_BLOCK_BITS / 8];
|
||
|
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 );
|
||
|
@@ -806,17 +709,45 @@ NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDL
|
||
|
hash->alg_id = alg->id;
|
||
|
hash->hmac = alg->hmac;
|
||
|
|
||
|
- if (hash->hmac)
|
||
|
+ status = hash_init( &hash->inner, hash->alg_id );
|
||
|
+ if (status || !hash->hmac) goto end;
|
||
|
+ status = hash_init( &hash->outer, hash->alg_id );
|
||
|
+ if (status) goto end;
|
||
|
+
|
||
|
+ /* reduce key size if too big */
|
||
|
+ block_bytes = alg_block_bits[hash->alg_id] / 8;
|
||
|
+ if (secretlen > block_bytes)
|
||
|
{
|
||
|
- status = hmac_init( hash, secret, secretlen );
|
||
|
+ struct hash_impl temp;
|
||
|
+ status = hash_init( &temp, hash->alg_id );
|
||
|
+ if (status) goto end;
|
||
|
+ status = hash_update( &temp, hash->alg_id, secret, secretlen );
|
||
|
+ if (status) goto end;
|
||
|
+ memset( buffer, 0, block_bytes );
|
||
|
+ status = hash_finish( &temp, hash->alg_id, buffer, alg_props[hash->alg_id].hash_length );
|
||
|
+ if (status) goto end;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
- status = hash_init( hash );
|
||
|
+ memset( buffer, 0, block_bytes );
|
||
|
+ memcpy( buffer, secret, secretlen );
|
||
|
}
|
||
|
|
||
|
+ /* initialize outer hash */
|
||
|
+ for (i = 0; i < block_bytes; i++)
|
||
|
+ buffer[i] ^= 0x5c;
|
||
|
+ status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes );
|
||
|
+ if (status) goto end;
|
||
|
+
|
||
|
+ /* initialize inner hash */
|
||
|
+ for (i = 0; i < block_bytes; i++)
|
||
|
+ buffer[i] ^= (0x5c ^ 0x36);
|
||
|
+ status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
|
||
|
+
|
||
|
+end:
|
||
|
if (status != STATUS_SUCCESS)
|
||
|
{
|
||
|
+ /* FIXME: call hash_finish to release resources */
|
||
|
HeapFree( GetProcessHeap(), 0, hash );
|
||
|
return status;
|
||
|
}
|
||
|
@@ -845,33 +776,33 @@ 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;
|
||
|
|
||
|
- if (hash->hmac)
|
||
|
- {
|
||
|
- return hmac_update( hash, input, size );
|
||
|
- }
|
||
|
- else
|
||
|
- {
|
||
|
- return hash_update( hash, 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 )
|
||
|
{
|
||
|
+ UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
|
||
|
struct hash *hash = handle;
|
||
|
+ NTSTATUS status;
|
||
|
+ int hash_size;
|
||
|
|
||
|
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->hmac)
|
||
|
- {
|
||
|
- return hmac_finish( hash, output, size );
|
||
|
- }
|
||
|
- else
|
||
|
- {
|
||
|
- return hash_finish( hash, output, size );
|
||
|
- }
|
||
|
+ if (!hash->hmac)
|
||
|
+ return hash_finish( &hash->inner, hash->alg_id, output, size );
|
||
|
+
|
||
|
+ hash_size = alg_props[hash->alg_id].hash_length;
|
||
|
+
|
||
|
+ status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_size);
|
||
|
+ if (status) return status;
|
||
|
+
|
||
|
+ status = hash_update( &hash->outer, hash->alg_id, buffer, hash_size);
|
||
|
+ if (status) return status;
|
||
|
+
|
||
|
+ return hash_finish( &hash->outer, hash->alg_id, output, size);
|
||
|
}
|
||
|
|
||
|
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
|
||
|
--
|
||
|
2.9.0
|
||
|
|