bcrypt: Implement BCryptDeriveKey().
This commit is contained in:
parent
cfa655c4a3
commit
81d71ee0bb
3 changed files with 201 additions and 20 deletions
|
@ -302,6 +302,15 @@ struct key_asymmetric_import_params
|
|||
ULONG len;
|
||||
};
|
||||
|
||||
struct key_asymmetric_derive_key_params
|
||||
{
|
||||
struct key *privkey;
|
||||
struct key *pubkey;
|
||||
UCHAR *output;
|
||||
ULONG output_len;
|
||||
ULONG *ret_len;
|
||||
};
|
||||
|
||||
enum key_funcs
|
||||
{
|
||||
unix_process_attach,
|
||||
|
@ -321,6 +330,7 @@ enum key_funcs
|
|||
unix_key_asymmetric_destroy,
|
||||
unix_key_asymmetric_export,
|
||||
unix_key_asymmetric_import,
|
||||
unix_key_asymmetric_derive_key,
|
||||
unix_funcs_count,
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -1134,24 +1135,13 @@ NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULON
|
|||
return hash_finalize( hash, output );
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secret_len,
|
||||
UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len )
|
||||
static NTSTATUS hash_single( struct algorithm *alg, UCHAR *secret, ULONG secret_len, UCHAR *input, ULONG input_len,
|
||||
UCHAR *output, ULONG output_len )
|
||||
{
|
||||
struct algorithm *alg = get_alg_object( handle );
|
||||
struct hash *hash;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE( "%p, %p, %lu, %p, %lu, %p, %lu\n", handle, secret, secret_len, input, input_len, output, output_len );
|
||||
|
||||
if (!alg) return STATUS_INVALID_HANDLE;
|
||||
if (!output) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if ((status = hash_create( alg, secret, secret_len, 0, &hash ))) return status;
|
||||
if (output_len != builtin_algorithms[hash->alg_id].hash_length)
|
||||
{
|
||||
hash_destroy( hash );
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
if ((status = hash_update( &hash->inner, hash->alg_id, input, input_len )))
|
||||
{
|
||||
hash_destroy( hash );
|
||||
|
@ -1162,6 +1152,19 @@ NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secre
|
|||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secret_len, UCHAR *input, ULONG input_len,
|
||||
UCHAR *output, ULONG output_len )
|
||||
{
|
||||
struct algorithm *alg = get_alg_object( handle );
|
||||
|
||||
TRACE( "%p, %p, %lu, %p, %lu, %p, %lu\n", handle, secret, secret_len, input, input_len, output, output_len );
|
||||
|
||||
if (!alg) return STATUS_INVALID_HANDLE;
|
||||
if (!output || output_len != builtin_algorithms[alg->id].hash_length) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
return hash_single(alg, secret, secret_len, input, input_len, output, output_len );
|
||||
}
|
||||
|
||||
static NTSTATUS key_asymmetric_create( enum alg_id alg_id, ULONG bitlen, struct key **ret_key )
|
||||
{
|
||||
struct key *key;
|
||||
|
@ -2471,17 +2474,118 @@ NTSTATUS WINAPI BCryptDestroySecret( BCRYPT_SECRET_HANDLE handle )
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, BCryptBufferDesc *parameter,
|
||||
UCHAR *derived, ULONG derived_size, ULONG *result, ULONG flags )
|
||||
static void reverse_bytes( UCHAR *buf, ULONG len )
|
||||
{
|
||||
ULONG i;
|
||||
for (i = 0; i < len / 2; i++)
|
||||
{
|
||||
UCHAR tmp = buf[i];
|
||||
buf[i] = buf[len - i - 1];
|
||||
buf[len - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS derive_key_raw( struct secret *secret, UCHAR *output, ULONG output_len, ULONG *ret_len )
|
||||
{
|
||||
struct key_asymmetric_derive_key_params params;
|
||||
NTSTATUS status;
|
||||
|
||||
params.privkey = secret->privkey;
|
||||
params.pubkey = secret->pubkey;
|
||||
params.output = output;
|
||||
params.output_len = output_len;
|
||||
params.ret_len = ret_len;
|
||||
if (!(status = UNIX_CALL( key_asymmetric_derive_key, ¶ms )) && output) reverse_bytes( output, *ret_len );
|
||||
return status;
|
||||
}
|
||||
|
||||
static BCRYPT_ALG_HANDLE hash_handle_from_desc( BCryptBufferDesc *desc )
|
||||
{
|
||||
ULONG i;
|
||||
if (!desc) return BCRYPT_SHA1_ALG_HANDLE;
|
||||
for (i = 0; i < desc->cBuffers; i++)
|
||||
{
|
||||
if (desc->pBuffers[i].BufferType == KDF_HASH_ALGORITHM)
|
||||
{
|
||||
const WCHAR *str = desc->pBuffers[i].pvBuffer;
|
||||
if (!wcscmp( str, BCRYPT_SHA1_ALGORITHM )) return BCRYPT_SHA1_ALG_HANDLE;
|
||||
else if (!wcscmp( str, BCRYPT_SHA256_ALGORITHM )) return BCRYPT_SHA256_ALG_HANDLE;
|
||||
else if (!wcscmp( str, BCRYPT_SHA384_ALGORITHM )) return BCRYPT_SHA384_ALG_HANDLE;
|
||||
else if (!wcscmp( str, BCRYPT_SHA512_ALGORITHM )) return BCRYPT_SHA512_ALG_HANDLE;
|
||||
else
|
||||
{
|
||||
FIXME( "hash algorithm %s not supported\n", debugstr_w(str) );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else FIXME( "buffer type %lu not supported\n", desc->pBuffers[i].BufferType );
|
||||
}
|
||||
|
||||
return BCRYPT_SHA1_ALG_HANDLE;
|
||||
}
|
||||
|
||||
static NTSTATUS derive_key_hash( struct secret *secret, BCryptBufferDesc *desc, UCHAR *output, ULONG output_len,
|
||||
ULONG *ret_len )
|
||||
{
|
||||
struct key_asymmetric_derive_key_params params;
|
||||
struct algorithm *alg = get_alg_object( hash_handle_from_desc(desc) );
|
||||
ULONG hash_len, derived_key_len = secret->privkey->u.a.bitlen / 8;
|
||||
UCHAR hash_buf[MAX_HASH_OUTPUT_BYTES];
|
||||
UCHAR *derived_key;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!alg) return STATUS_NOT_SUPPORTED;
|
||||
if (!(derived_key = malloc( derived_key_len ))) return STATUS_NO_MEMORY;
|
||||
|
||||
params.privkey = secret->privkey;
|
||||
params.pubkey = secret->pubkey;
|
||||
params.output = derived_key;
|
||||
params.output_len = derived_key_len;
|
||||
params.ret_len = ret_len;
|
||||
if ((status = UNIX_CALL( key_asymmetric_derive_key, ¶ms )))
|
||||
{
|
||||
free( derived_key );
|
||||
return status;
|
||||
}
|
||||
|
||||
hash_len = builtin_algorithms[alg->id].hash_length;
|
||||
assert( hash_len <= sizeof(hash_buf) );
|
||||
if (!(status = hash_single( alg, NULL, 0, derived_key, *params.ret_len, hash_buf, hash_len )))
|
||||
{
|
||||
if (!output) *ret_len = hash_len;
|
||||
else
|
||||
{
|
||||
*ret_len = min( hash_len, output_len );
|
||||
memcpy( output, hash_buf, *ret_len );
|
||||
}
|
||||
}
|
||||
|
||||
free( derived_key );
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, BCryptBufferDesc *desc,
|
||||
UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags )
|
||||
{
|
||||
struct secret *secret = get_secret_object( handle );
|
||||
|
||||
FIXME( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags );
|
||||
TRACE( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), desc, output, output_len,
|
||||
ret_len, flags );
|
||||
|
||||
if (!secret) return STATUS_INVALID_HANDLE;
|
||||
if (!kdf) return STATUS_INVALID_PARAMETER;
|
||||
if (!kdf || !ret_len) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
if (!wcscmp(kdf, BCRYPT_KDF_RAW_SECRET))
|
||||
{
|
||||
return derive_key_raw( secret, output, output_len, ret_len );
|
||||
}
|
||||
else if (!wcscmp(kdf, BCRYPT_KDF_HASH))
|
||||
{
|
||||
return derive_key_hash( secret, desc, output, output_len, ret_len );
|
||||
}
|
||||
|
||||
FIXME( "kdf %s not supportedi\n", debugstr_w(kdf) );
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
|
||||
|
|
|
@ -144,6 +144,10 @@ static void (*pgnutls_x509_spki_set_rsa_pss_params)(gnutls_x509_spki_t, gnutls_d
|
|||
static int (*pgnutls_pubkey_set_spki)(gnutls_pubkey_t, const gnutls_x509_spki_t, unsigned int);
|
||||
static int (*pgnutls_privkey_set_spki)(gnutls_privkey_t, const gnutls_x509_spki_t, unsigned int);
|
||||
|
||||
/* Not present in gnutls version < 3.8.2 */
|
||||
static int (*pgnutls_privkey_derive_secret)(gnutls_privkey_t, gnutls_pubkey_t, const gnutls_datum_t *,
|
||||
gnutls_datum_t *, unsigned int);
|
||||
|
||||
static void *libgnutls_handle;
|
||||
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
|
||||
MAKE_FUNCPTR(gnutls_cipher_decrypt2);
|
||||
|
@ -302,6 +306,12 @@ static int compat_gnutls_privkey_set_spki(gnutls_privkey_t key, const gnutls_x50
|
|||
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
|
||||
}
|
||||
|
||||
static int compat_gnutls_privkey_derive_secret(gnutls_privkey_t privkey, gnutls_pubkey_t pubkey, const gnutls_datum_t *nonce,
|
||||
gnutls_datum_t *secret, unsigned int flags)
|
||||
{
|
||||
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
|
||||
}
|
||||
|
||||
static void gnutls_log( int level, const char *msg )
|
||||
{
|
||||
TRACE( "<%d> %s", level, msg );
|
||||
|
@ -365,6 +375,7 @@ static NTSTATUS gnutls_process_attach( void *args )
|
|||
LOAD_FUNCPTR_OPT(gnutls_decode_rs_value)
|
||||
LOAD_FUNCPTR_OPT(gnutls_pk_to_sign)
|
||||
LOAD_FUNCPTR_OPT(gnutls_privkey_decrypt_data)
|
||||
LOAD_FUNCPTR_OPT(gnutls_privkey_derive_secret)
|
||||
LOAD_FUNCPTR_OPT(gnutls_privkey_export_dsa_raw)
|
||||
LOAD_FUNCPTR_OPT(gnutls_privkey_export_ecc_raw)
|
||||
LOAD_FUNCPTR_OPT(gnutls_privkey_export_rsa_raw)
|
||||
|
@ -2250,6 +2261,30 @@ static NTSTATUS key_asymmetric_encrypt( void *args )
|
|||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS key_asymmetric_derive_key( void *args )
|
||||
{
|
||||
const struct key_asymmetric_derive_key_params *params = args;
|
||||
gnutls_datum_t s;
|
||||
int ret;
|
||||
|
||||
if ((ret = pgnutls_privkey_derive_secret( key_data(params->privkey)->a.privkey,
|
||||
key_data(params->pubkey)->a.pubkey, NULL, &s, 0 )))
|
||||
{
|
||||
pgnutls_perror( ret );
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!params->output) *params->ret_len = s.size;
|
||||
else
|
||||
{
|
||||
*params->ret_len = min( params->output_len, s.size );
|
||||
memcpy( params->output, s.data, *params->ret_len );
|
||||
}
|
||||
|
||||
free( s.data );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
const unixlib_entry_t __wine_unix_call_funcs[] =
|
||||
{
|
||||
gnutls_process_attach,
|
||||
|
@ -2268,7 +2303,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
|
|||
key_asymmetric_verify,
|
||||
key_asymmetric_destroy,
|
||||
key_asymmetric_export,
|
||||
key_asymmetric_import
|
||||
key_asymmetric_import,
|
||||
key_asymmetric_derive_key,
|
||||
};
|
||||
|
||||
C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count );
|
||||
|
@ -2733,6 +2769,36 @@ static NTSTATUS wow64_key_asymmetric_import( void *args )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static NTSTATUS wow64_key_asymmetric_derive_key( void *args )
|
||||
{
|
||||
struct
|
||||
{
|
||||
PTR32 privkey;
|
||||
PTR32 pubkey;
|
||||
PTR32 output;
|
||||
ULONG output_len;
|
||||
PTR32 ret_len;
|
||||
} const *params32 = args;
|
||||
|
||||
NTSTATUS ret;
|
||||
struct key privkey, pubkey;
|
||||
struct key32 *privkey32 = ULongToPtr( params32->privkey );
|
||||
struct key32 *pubkey32 = ULongToPtr( params32->pubkey );
|
||||
struct key_asymmetric_derive_key_params params =
|
||||
{
|
||||
get_asymmetric_key( privkey32, &privkey ),
|
||||
get_asymmetric_key( pubkey32, &pubkey ),
|
||||
ULongToPtr(params32->output),
|
||||
params32->output_len,
|
||||
ULongToPtr(params32->ret_len),
|
||||
};
|
||||
|
||||
ret = key_asymmetric_derive_key( ¶ms );
|
||||
put_asymmetric_key32( &privkey, privkey32 );
|
||||
put_asymmetric_key32( &pubkey, pubkey32 );
|
||||
return ret;
|
||||
}
|
||||
|
||||
const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
|
||||
{
|
||||
gnutls_process_attach,
|
||||
|
@ -2751,7 +2817,8 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
|
|||
wow64_key_asymmetric_verify,
|
||||
wow64_key_asymmetric_destroy,
|
||||
wow64_key_asymmetric_export,
|
||||
wow64_key_asymmetric_import
|
||||
wow64_key_asymmetric_import,
|
||||
wow64_key_asymmetric_derive_key,
|
||||
};
|
||||
|
||||
C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count );
|
||||
|
|
Loading…
Add table
Reference in a new issue