-- v2: bcrypt: Add support for BCRYPT_AES_WRAP_KEY_BLOB in BCryptImportKey(). bcrypt: Add support for BCRYPT_AES_WRAP_KEY_BLOB in BCryptExportKey().
From: Hans Leidekker hans@codeweavers.com
And rename the functions for consistency. --- dlls/bcrypt/bcrypt_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index ec1004760f0..e1c971c1485 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1129,7 +1129,7 @@ static NTSTATUS key_symmetric_set_vector( struct key *key, UCHAR *vector, ULONG return STATUS_SUCCESS; }
-static struct key *create_symmetric_key( enum alg_id alg, enum chain_mode mode, ULONG block_size, UCHAR *secret, +static struct key *key_symmetric_create( enum alg_id alg, enum chain_mode mode, ULONG block_size, const UCHAR *secret, ULONG secret_len ) { struct key *ret; @@ -1160,7 +1160,7 @@ static ULONG get_block_size( struct algorithm *alg ) return ret; }
-static NTSTATUS generate_symmetric_key( struct algorithm *alg, BCRYPT_KEY_HANDLE *ret_handle, UCHAR *secret, +static NTSTATUS key_symmetric_generate( struct algorithm *alg, BCRYPT_KEY_HANDLE *ret_handle, const UCHAR *secret, ULONG secret_len ) { BCRYPT_KEY_LENGTHS_STRUCT key_lengths; @@ -1188,7 +1188,7 @@ static NTSTATUS generate_symmetric_key( struct algorithm *alg, BCRYPT_KEY_HANDLE } }
- if (!(key = create_symmetric_key( alg->id, alg->mode, block_size, secret, secret_len ))) status = STATUS_NO_MEMORY; + if (!(key = key_symmetric_create( alg->id, alg->mode, block_size, secret, secret_len ))) status = STATUS_NO_MEMORY; else { *ret_handle = key; @@ -1217,7 +1217,7 @@ static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY len = header->cbKeyData; if (len + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len) return STATUS_INVALID_PARAMETER;
- return generate_symmetric_key( alg, key, (UCHAR *)&header[1], len ); + return key_symmetric_generate( alg, key, (UCHAR *)&header[1], len ); } else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) { @@ -1225,7 +1225,7 @@ static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY len = *(ULONG *)input; if (len + sizeof(len) > input_len) return STATUS_INVALID_PARAMETER;
- return generate_symmetric_key( alg, key, input + sizeof(len), len ); + return key_symmetric_generate( alg, key, input + sizeof(len), len ); }
FIXME( "unsupported key type %s\n", debugstr_w(type) ); @@ -1879,7 +1879,7 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY }
if (!alg) return STATUS_INVALID_HANDLE; - if ((status = generate_symmetric_key( alg, ret_handle, secret, secret_len ))) return status; + if ((status = key_symmetric_generate( alg, ret_handle, secret, secret_len ))) return status; TRACE( "returning handle %p\n", *ret_handle ); return STATUS_SUCCESS; }
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index e1c971c1485..31d2de00e7b 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1392,7 +1392,8 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp memcpy( key->u.s.vector, output + *ret_len - key->u.s.vector_len, key->u.s.vector_len ); if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); } - else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + else if (key->u.s.vector) + FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); }
return status;
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 241 +++++++++++++++++++++++-------------- dlls/bcrypt/tests/bcrypt.c | 4 - 2 files changed, 152 insertions(+), 93 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 31d2de00e7b..6fb6a44044e 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1153,6 +1153,21 @@ static struct key *key_symmetric_create( enum alg_id alg, enum chain_mode mode, return ret; }
+static void key_destroy( struct key *key ) +{ + if (is_symmetric_key( key )) + { + UNIX_CALL( key_symmetric_destroy, key ); + free( key->u.s.vector ); + free( key->u.s.secret ); + DeleteCriticalSection( &key->u.s.cs ); + } + else + UNIX_CALL( key_asymmetric_destroy, key ); + + destroy_object( &key->hdr ); +} + static ULONG get_block_size( struct algorithm *alg ) { ULONG ret = 0, size = sizeof(ret); @@ -1232,74 +1247,6 @@ static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY return STATUS_NOT_IMPLEMENTED; }
-static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size ) -{ - struct key_asymmetric_export_params params; - - if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) - { - BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output; - ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->u.s.secret_len; - - *size = req_size; - if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; - if (output) - { - header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; - header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; - header->cbKeyData = key->u.s.secret_len; - memcpy( &header[1], key->u.s.secret, key->u.s.secret_len ); - } - return STATUS_SUCCESS; - } - else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) - { - ULONG len, req_size = sizeof(len) + key->u.s.secret_len; - - *size = req_size; - if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; - if (output) - { - *(ULONG *)output = key->u.s.secret_len; - memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len ); - } - return STATUS_SUCCESS; - } - else if (!wcscmp( type, BCRYPT_DSA_PRIVATE_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB ) || - !wcscmp( type, BCRYPT_ECCPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) - { - params.key = key; - params.flags = 0; - params.buf = output; - params.len = output_len; - params.ret_len = size; - return UNIX_CALL( key_asymmetric_export, ¶ms ); - } - else if (!wcscmp( type, BCRYPT_RSAPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_RSAFULLPRIVATE_BLOB )) - { - params.key = key; - params.flags = (wcscmp( type, BCRYPT_RSAPRIVATE_BLOB )) ? KEY_EXPORT_FLAG_RSA_FULL : 0; - params.buf = output; - params.len = output_len; - params.ret_len = size; - return UNIX_CALL( key_asymmetric_export, ¶ms ); - } - else if (!wcscmp( type, BCRYPT_DSA_PUBLIC_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB ) || - !wcscmp( type, BCRYPT_ECCPUBLIC_BLOB ) || !wcscmp( type, BCRYPT_RSAPUBLIC_BLOB ) || - !wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) - { - params.key = key; - params.flags = KEY_EXPORT_FLAG_PUBLIC; - params.buf = output; - params.len = output_len; - params.ret_len = size; - return UNIX_CALL( key_asymmetric_export, ¶ms ); - } - - FIXME( "unsupported key type %s\n", debugstr_w(type) ); - return STATUS_NOT_IMPLEMENTED; -} - static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) { @@ -1399,6 +1346,140 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp return status; }
+/* AES Key Wrap Algorithm (RFC3394) */ +static NTSTATUS aes_wrap( const UCHAR *secret, ULONG secret_len, const UCHAR *plain, UCHAR *cipher ) +{ + UCHAR *a, *r, b[16]; + ULONG len, t, i, j, n = secret_len / 8; + struct key *key; + + a = cipher; + r = cipher + 8; + + memset( a, 0xa6, 8 ); + memcpy( r, plain, 8 * n ); + + if (!(key = key_symmetric_create( ALG_ID_AES, CHAIN_MODE_ECB, 16, secret, secret_len ))) return STATUS_NO_MEMORY; + + for (j = 0; j <= 5; j++) + { + r = cipher + 8; + for (i = 1; i <= n; i++) + { + memcpy( b, a, 8 ); + memcpy( b + 8, r, 8 ); + key_symmetric_encrypt( key, b, 16, NULL, NULL, 0, b, 16, &len, 0 ); + memcpy( a, b, 8 ); + t = n * j + i; + a[7] ^= t; + a[6] ^= t >> 8; + a[5] ^= t >> 16; + a[4] ^= t >> 24; + memcpy( r, b + 8, 8 ); + r += 8; + } + } + + key_destroy( key ); + return STATUS_SUCCESS; +} + +static NTSTATUS key_export( struct key *key, struct key *encrypt_key, const WCHAR *type, UCHAR *output, + ULONG output_len, ULONG *size ) +{ + struct key_asymmetric_export_params params; + NTSTATUS status; + + if (encrypt_key && wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) + { + FIXME( "encryption of key not supported\n" ); + return STATUS_NOT_IMPLEMENTED; + } + + if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) + { + BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output; + ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->u.s.secret_len; + + *size = req_size; + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + if (output) + { + header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; + header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; + header->cbKeyData = key->u.s.secret_len; + memcpy( &header[1], key->u.s.secret, key->u.s.secret_len ); + } + return STATUS_SUCCESS; + } + else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) + { + ULONG len, req_size = sizeof(len) + key->u.s.secret_len; + + *size = req_size; + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + if (output) + { + *(ULONG *)output = key->u.s.secret_len; + memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len ); + } + return STATUS_SUCCESS; + } + else if (!wcscmp( type, BCRYPT_DSA_PRIVATE_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB ) || + !wcscmp( type, BCRYPT_ECCPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) + { + params.key = key; + params.flags = 0; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); + } + else if (!wcscmp( type, BCRYPT_RSAPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_RSAFULLPRIVATE_BLOB )) + { + params.key = key; + params.flags = (wcscmp( type, BCRYPT_RSAPRIVATE_BLOB )) ? KEY_EXPORT_FLAG_RSA_FULL : 0; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); + } + else if (!wcscmp( type, BCRYPT_DSA_PUBLIC_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB ) || + !wcscmp( type, BCRYPT_ECCPUBLIC_BLOB ) || !wcscmp( type, BCRYPT_RSAPUBLIC_BLOB ) || + !wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) + { + params.key = key; + params.flags = KEY_EXPORT_FLAG_PUBLIC; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); + } + else if (!wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) + { + ULONG req_size = key->u.s.secret_len + 8; + + if (!encrypt_key) return STATUS_INVALID_PARAMETER; + if (key->u.s.secret_len > BLOCK_LENGTH_AES) + { + FIXME( "key length %u not supported yet\n", key->u.s.secret_len ); + return STATUS_NOT_IMPLEMENTED; + } + + *size = req_size; + if (output) + { + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + if ((status = aes_wrap( encrypt_key->u.s.secret, encrypt_key->u.s.secret_len, key->u.s.secret, output ))) + return status; + } + return STATUS_SUCCESS; + } + + FIXME( "unsupported key type %s\n", debugstr_w(type) ); + return STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) { @@ -1506,21 +1587,6 @@ static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG inpu return status; }
-static void key_destroy( struct key *key ) -{ - if (is_symmetric_key( key )) - { - UNIX_CALL( key_symmetric_destroy, key ); - free( key->u.s.vector ); - free( key->u.s.secret ); - DeleteCriticalSection( &key->u.s.cs ); - } - else - UNIX_CALL( key_asymmetric_destroy, key ); - - destroy_object( &key->hdr ); -} - static NTSTATUS convert_legacy_rsaprivate_blob( struct algorithm *alg, BCRYPT_RSAKEY_BLOB **rsa_data, ULONG *rsa_len, UCHAR *input, ULONG input_len ) { @@ -1943,19 +2009,16 @@ NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key_handle, BCRYPT_KEY const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size, ULONG flags ) { struct key *key = get_key_object( export_key_handle ); + struct key *encrypt_key = NULL;
TRACE( "%p, %p, %s, %p, %lu, %p, %#lx\n", export_key_handle, encrypt_key_handle, debugstr_w(type), output, output_len, size, flags );
if (!key) return STATUS_INVALID_HANDLE; if (!type || !size) return STATUS_INVALID_PARAMETER; - if (encrypt_key_handle) - { - FIXME( "encryption of key not yet supported\n" ); - return STATUS_NOT_IMPLEMENTED; - } + if (encrypt_key_handle && !(encrypt_key = get_key_object( encrypt_key_handle ))) return STATUS_INVALID_HANDLE;
- return key_export( key, type, output, output_len, size ); + return key_export( key, encrypt_key, type, output, output_len, size ); }
static NTSTATUS key_duplicate( struct key *key_orig, struct key **ret_key ) diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 7e33dcf201c..bf3221a7943 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2111,15 +2111,11 @@ static void test_key_import_export(void)
size = 0; ret = BCryptExportKey(key, key2, BCRYPT_AES_WRAP_KEY_BLOB, NULL, 0, &size, 0); - todo_wine ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine ok(size == sizeof(buffer3), "got %lu\n", size);
ret = BCryptExportKey(key, key2, BCRYPT_AES_WRAP_KEY_BLOB, buffer3, size, &size, 0); - todo_wine ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine ok(!memcmp(buffer3, encrypted_blob, sizeof(encrypted_blob)), "blobs didn't match\n");
key3 = NULL;
From: Hans Leidekker hans@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57492 --- dlls/bcrypt/bcrypt_main.c | 300 ++++++++++++++++++++++--------------- dlls/bcrypt/tests/bcrypt.c | 5 - 2 files changed, 182 insertions(+), 123 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 6fb6a44044e..04422fdbaae 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1213,10 +1213,165 @@ static NTSTATUS key_symmetric_generate( struct algorithm *alg, BCRYPT_KEY_HANDLE return status; }
-static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY_HANDLE *key, UCHAR *object, - ULONG object_len, UCHAR *input, ULONG input_len ) +static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, + ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) +{ + struct key_symmetric_set_auth_data_params auth_params; + struct key_symmetric_decrypt_params decrypt_params; + struct key_symmetric_get_tag_params tag_params; + ULONG bytes_left = input_len; + NTSTATUS status; + + if (key->u.s.mode == CHAIN_MODE_GCM) + { + BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; + UCHAR tag[16]; + + if (!auth_info) return STATUS_INVALID_PARAMETER; + if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER; + if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER; + if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER; + + if ((status = key_symmetric_set_vector( key, auth_info->pbNonce, auth_info->cbNonce, TRUE ))) + return status; + + *ret_len = input_len; + if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER; + if (!output) return STATUS_SUCCESS; + if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; + + auth_params.key = key; + auth_params.auth_data = auth_info->pbAuthData; + auth_params.len = auth_info->cbAuthData; + if ((status = UNIX_CALL( key_symmetric_set_auth_data, &auth_params ))) return status; + + decrypt_params.key = key; + decrypt_params.input = input; + decrypt_params.input_len = input_len; + decrypt_params.output = output; + decrypt_params.output_len = output_len; + if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; + + tag_params.key = key; + tag_params.tag = tag; + tag_params.len = sizeof(tag); + if ((status = UNIX_CALL( key_symmetric_get_tag, &tag_params ))) return status; + if (memcmp( tag, auth_info->pbTag, auth_info->cbTag )) return STATUS_AUTH_TAG_MISMATCH; + + return STATUS_SUCCESS; + } + + *ret_len = input_len; + + if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE; + if (!output) return STATUS_SUCCESS; + if (flags & BCRYPT_BLOCK_PADDING) + { + if (output_len + key->u.s.block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL; + if (input_len < key->u.s.block_size) return STATUS_BUFFER_TOO_SMALL; + bytes_left -= key->u.s.block_size; + } + else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; + + if (key->u.s.mode == CHAIN_MODE_ECB && iv) return STATUS_INVALID_PARAMETER; + if ((status = key_symmetric_set_vector( key, iv, iv_len, flags & BCRYPT_BLOCK_PADDING ))) return status; + + decrypt_params.key = key; + decrypt_params.input = input; + decrypt_params.input_len = key->u.s.block_size; + decrypt_params.output = output; + decrypt_params.output_len = key->u.s.block_size; + while (bytes_left >= key->u.s.block_size) + { + if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; + if (key->u.s.mode == CHAIN_MODE_ECB && (status = key_symmetric_set_vector( key, NULL, 0, TRUE ))) + return status; + bytes_left -= key->u.s.block_size; + decrypt_params.input += key->u.s.block_size; + decrypt_params.output += key->u.s.block_size; + } + + if (flags & BCRYPT_BLOCK_PADDING) + { + UCHAR *buf, *dst = decrypt_params.output; + if (!(buf = malloc( key->u.s.block_size ))) return STATUS_NO_MEMORY; + decrypt_params.output = buf; + status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ); + if (!status && buf[ key->u.s.block_size - 1 ] <= key->u.s.block_size) + { + *ret_len -= buf[ key->u.s.block_size - 1 ]; + if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL; + else memcpy( dst, buf, key->u.s.block_size - buf[ key->u.s.block_size - 1 ] ); + } + else status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */ + free( buf ); + } + + if (!status) + { + if (key->u.s.vector && input_len >= key->u.s.vector_len) + { + memcpy( key->u.s.vector, input + input_len - key->u.s.vector_len, key->u.s.vector_len ); + if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + } + else if (key->u.s.vector) + FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + } + + return status; +} + +/* AES Key Wrap Algorithm (RFC3394) */ +static NTSTATUS aes_unwrap( const UCHAR *secret, ULONG secret_len, const UCHAR *cipher, UCHAR *plain ) +{ + UCHAR a[8], *r, b[16]; + ULONG len, t, i, n = secret_len / 8; + int j; + struct key *key; + + memcpy( a, cipher, 8 ); + r = plain; + memcpy( r, cipher + 8, 8 * n ); + + if (!(key = key_symmetric_create( ALG_ID_AES, CHAIN_MODE_ECB, 16, secret, secret_len ))) return STATUS_NO_MEMORY; + + for (j = 5; j >= 0; j--) + { + r = plain + (n - 1) * 8; + for (i = n; i >= 1; i--) + { + memcpy( b, a, 8 ); + t = n * j + i; + b[7] ^= t; + b[6] ^= t >> 8; + b[5] ^= t >> 16; + b[4] ^= t >> 24; + + memcpy( b + 8, r, 8 ); + key_symmetric_decrypt( key, b, 16, NULL, NULL, 0, b, 16, &len, 0 ); + memcpy( a, b, 8 ); + memcpy( r, b + 8, 8 ); + r -= 8; + } + } + + key_destroy( key ); + + for (i = 0; i < 8; i++) if (a[i] != 0xa6) return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; +} + +static NTSTATUS key_import( struct algorithm *alg, struct key *decrypt_key, const WCHAR *type, BCRYPT_KEY_HANDLE *key, + UCHAR *object, ULONG object_len, UCHAR *input, ULONG input_len ) { ULONG len; + NTSTATUS status; + + if (decrypt_key && wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) + { + FIXME( "decryption of key not supported\n" ); + return STATUS_NOT_IMPLEMENTED; + }
if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) { @@ -1242,6 +1397,25 @@ static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY
return key_symmetric_generate( alg, key, input + sizeof(len), len ); } + else if (!wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) + { + UCHAR output[BLOCK_LENGTH_AES]; + + if (!decrypt_key || input_len < 8) return STATUS_INVALID_PARAMETER; + + len = input_len - 8; + if (len < BLOCK_LENGTH_AES || len & (BLOCK_LENGTH_AES - 1)) return STATUS_INVALID_PARAMETER; + if (len > sizeof(output)) + { + FIXME( "key length %lu not supported yet\n", len ); + return STATUS_NOT_IMPLEMENTED; + } + + if ((status = aes_unwrap( decrypt_key->u.s.secret, decrypt_key->u.s.secret_len, input, output ))) + return status; + + return key_symmetric_generate( alg, key, output, len ); + }
FIXME( "unsupported key type %s\n", debugstr_w(type) ); return STATUS_NOT_IMPLEMENTED; @@ -1480,113 +1654,6 @@ static NTSTATUS key_export( struct key *key, struct key *encrypt_key, const WCHA return STATUS_NOT_IMPLEMENTED; }
-static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, - ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) -{ - struct key_symmetric_set_auth_data_params auth_params; - struct key_symmetric_decrypt_params decrypt_params; - struct key_symmetric_get_tag_params tag_params; - ULONG bytes_left = input_len; - NTSTATUS status; - - if (key->u.s.mode == CHAIN_MODE_GCM) - { - BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; - UCHAR tag[16]; - - if (!auth_info) return STATUS_INVALID_PARAMETER; - if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER; - if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER; - if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER; - - if ((status = key_symmetric_set_vector( key, auth_info->pbNonce, auth_info->cbNonce, TRUE ))) - return status; - - *ret_len = input_len; - if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER; - if (!output) return STATUS_SUCCESS; - if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; - - auth_params.key = key; - auth_params.auth_data = auth_info->pbAuthData; - auth_params.len = auth_info->cbAuthData; - if ((status = UNIX_CALL( key_symmetric_set_auth_data, &auth_params ))) return status; - - decrypt_params.key = key; - decrypt_params.input = input; - decrypt_params.input_len = input_len; - decrypt_params.output = output; - decrypt_params.output_len = output_len; - if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; - - tag_params.key = key; - tag_params.tag = tag; - tag_params.len = sizeof(tag); - if ((status = UNIX_CALL( key_symmetric_get_tag, &tag_params ))) return status; - if (memcmp( tag, auth_info->pbTag, auth_info->cbTag )) return STATUS_AUTH_TAG_MISMATCH; - - return STATUS_SUCCESS; - } - - *ret_len = input_len; - - if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE; - if (!output) return STATUS_SUCCESS; - if (flags & BCRYPT_BLOCK_PADDING) - { - if (output_len + key->u.s.block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL; - if (input_len < key->u.s.block_size) return STATUS_BUFFER_TOO_SMALL; - bytes_left -= key->u.s.block_size; - } - else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; - - if (key->u.s.mode == CHAIN_MODE_ECB && iv) return STATUS_INVALID_PARAMETER; - if ((status = key_symmetric_set_vector( key, iv, iv_len, flags & BCRYPT_BLOCK_PADDING ))) return status; - - decrypt_params.key = key; - decrypt_params.input = input; - decrypt_params.input_len = key->u.s.block_size; - decrypt_params.output = output; - decrypt_params.output_len = key->u.s.block_size; - while (bytes_left >= key->u.s.block_size) - { - if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; - if (key->u.s.mode == CHAIN_MODE_ECB && (status = key_symmetric_set_vector( key, NULL, 0, TRUE ))) - return status; - bytes_left -= key->u.s.block_size; - decrypt_params.input += key->u.s.block_size; - decrypt_params.output += key->u.s.block_size; - } - - if (flags & BCRYPT_BLOCK_PADDING) - { - UCHAR *buf, *dst = decrypt_params.output; - if (!(buf = malloc( key->u.s.block_size ))) return STATUS_NO_MEMORY; - decrypt_params.output = buf; - status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ); - if (!status && buf[ key->u.s.block_size - 1 ] <= key->u.s.block_size) - { - *ret_len -= buf[ key->u.s.block_size - 1 ]; - if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL; - else memcpy( dst, buf, key->u.s.block_size - buf[ key->u.s.block_size - 1 ] ); - } - else status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */ - free( buf ); - } - - if (!status) - { - if (key->u.s.vector && input_len >= key->u.s.vector_len) - { - memcpy( key->u.s.vector, input + input_len - key->u.s.vector_len, key->u.s.vector_len ); - if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); - } - else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); - } - - return status; -} - static NTSTATUS convert_legacy_rsaprivate_blob( struct algorithm *alg, BCRYPT_RSAKEY_BLOB **rsa_data, ULONG *rsa_len, UCHAR *input, ULONG input_len ) { @@ -1982,25 +2049,22 @@ NTSTATUS WINAPI BCryptFinalizeKeyPair( BCRYPT_KEY_HANDLE handle, ULONG flags ) return ret; }
-NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type, +NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE decrypt_key_handle, const WCHAR *type, BCRYPT_KEY_HANDLE *ret_handle, UCHAR *object, ULONG object_len, UCHAR *input, ULONG input_len, ULONG flags ) { struct algorithm *alg = get_alg_object( handle ); + struct key *decrypt_key = NULL; NTSTATUS status;
- TRACE( "%p, %p, %s, %p, %p, %lu, %p, %lu, %#lx\n", handle, decrypt_key, debugstr_w(type), ret_handle, object, - object_len, input, input_len, flags ); + TRACE( "%p, %p, %s, %p, %p, %lu, %p, %lu, %#lx\n", handle, decrypt_key_handle, debugstr_w(type), ret_handle, + object, object_len, input, input_len, flags );
if (!alg) return STATUS_INVALID_HANDLE; if (!ret_handle || !type || !input) return STATUS_INVALID_PARAMETER; - if (decrypt_key) - { - FIXME( "decryption of key not yet supported\n" ); - return STATUS_NOT_IMPLEMENTED; - } + if (decrypt_key_handle && !(decrypt_key = get_key_object( decrypt_key_handle ))) return STATUS_INVALID_HANDLE;
- if ((status = key_import( alg, type, ret_handle, object, object_len, input, input_len ))) return status; + if ((status = key_import( alg, decrypt_key, type, ret_handle, object, object_len, input, input_len ))) return status; TRACE( "returning handle %p\n", *ret_handle ); return STATUS_SUCCESS; } diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index bf3221a7943..abb19087a7d 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2120,19 +2120,14 @@ static void test_key_import_export(void)
key3 = NULL; ret = BCryptImportKey(aes, key2, BCRYPT_AES_WRAP_KEY_BLOB, &key3, NULL, 0, buffer3, sizeof(buffer3), 0); - todo_wine ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine ok(key3 != NULL, "key not set\n");
size = 0; memset(buffer2, 0xff, sizeof(buffer2)); ret = BCryptExportKey(key3, NULL, BCRYPT_KEY_DATA_BLOB, buffer2, sizeof(buffer2), &size, 0); - todo_wine ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine ok(size == sizeof(buffer2), "Got %lu\n", size); - todo_wine ok(!memcmp(buffer1, buffer2, sizeof(buffer1)), "Expected exported key to match imported key\n");
BCryptDestroyKey(key3);
v2: Add fixme for larger key lengths.