diff --git a/patches/bcrypt-Improvements/0028-bcrypt-Partial-implementation-of-BCryptImportKey-and.patch b/patches/bcrypt-Improvements/0028-bcrypt-Partial-implementation-of-BCryptImportKey-and.patch new file mode 100644 index 00000000..9d6bef02 --- /dev/null +++ b/patches/bcrypt-Improvements/0028-bcrypt-Partial-implementation-of-BCryptImportKey-and.patch @@ -0,0 +1,281 @@ +From f9a0c45bab75625d7ce4fcf0cbc49407e87a7a43 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sun, 13 Aug 2017 04:28:43 +0200 +Subject: bcrypt: Partial implementation of BCryptImportKey and + BCryptExportKey. + +--- + dlls/bcrypt/bcrypt.spec | 4 +- + dlls/bcrypt/bcrypt_main.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ + dlls/bcrypt/tests/bcrypt.c | 46 +++++++++++++++++++++ + include/bcrypt.h | 14 +++++++ + 4 files changed, 163 insertions(+), 2 deletions(-) + +diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec +index f5911d2cd40..f8a8c45a1d5 100644 +--- a/dlls/bcrypt/bcrypt.spec ++++ b/dlls/bcrypt/bcrypt.spec +@@ -20,7 +20,7 @@ + @ stub BCryptEnumContexts + @ stub BCryptEnumProviders + @ stub BCryptEnumRegisteredProviders +-@ stub BCryptExportKey ++@ stdcall BCryptExportKey(ptr ptr wstr ptr long ptr long) + @ stub BCryptFinalizeKeyPair + @ stdcall BCryptFinishHash(ptr ptr long long) + @ stub BCryptFreeBuffer +@@ -31,7 +31,7 @@ + @ stdcall BCryptGetProperty(ptr wstr ptr long ptr long) + @ stdcall BCryptHash(ptr ptr long ptr long ptr long) + @ stdcall BCryptHashData(ptr ptr long long) +-@ stub BCryptImportKey ++@ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) + @ stub BCryptImportKeyPair + @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) + @ stub BCryptQueryContextConfiguration +diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c +index d269083eca3..2b476484a52 100644 +--- a/dlls/bcrypt/bcrypt_main.c ++++ b/dlls/bcrypt/bcrypt_main.c +@@ -1007,6 +1007,13 @@ static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len ) + return STATUS_SUCCESS; + } + ++static NTSTATUS key_get_secret( struct key *key, UCHAR **secret, ULONG *len ) ++{ ++ *secret = key->secret; ++ *len = key->secret_len; ++ return STATUS_SUCCESS; ++} ++ + static NTSTATUS key_destroy( struct key *key ) + { + if (key->handle) pgnutls_cipher_deinit( key->handle ); +@@ -1074,6 +1081,12 @@ static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len ) + return STATUS_NOT_IMPLEMENTED; + } + ++static NTSTATUS key_get_secret( struct key *key, UCHAR **secret, ULONG *len ) ++{ ++ ERR( "support for keys not available at build time\n" ); ++ return STATUS_NOT_IMPLEMENTED; ++} ++ + static NTSTATUS key_destroy( struct key *key ) + { + ERR( "support for keys not available at build time\n" ); +@@ -1140,6 +1153,94 @@ NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE + return STATUS_SUCCESS; + } + ++NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type, ++ BCRYPT_KEY_HANDLE *key, UCHAR *object, ULONG object_len, UCHAR *input, ++ ULONG input_len, ULONG flags ) ++{ ++ struct algorithm *alg = algorithm; ++ ++ TRACE( "%p, %p, %s, %p, %p, %u, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), key, object, ++ object_len, input, input_len, flags ); ++ ++ if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE; ++ if (!key || !type || !input) return STATUS_INVALID_PARAMETER; ++ ++ if (decrypt_key) ++ { ++ FIXME( "decrypting of key not yet supported\n" ); ++ return STATUS_NOT_IMPLEMENTED; ++ } ++ ++ if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB )) ++ { ++ BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER *)input; ++ ++ if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)) ++ return STATUS_BUFFER_TOO_SMALL; ++ ++ if (key_header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC) ++ return STATUS_INVALID_PARAMETER; ++ ++ if (key_header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1) ++ { ++ FIXME( "unknown key data blob version %u\n", key_header->dwVersion ); ++ return STATUS_INVALID_PARAMETER; ++ } ++ ++ if (key_header->cbKeyData + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len) ++ return STATUS_INVALID_PARAMETER; ++ ++ return BCryptGenerateSymmetricKey( algorithm, key, object, object_len, ++ (UCHAR *)&key_header[1], key_header->cbKeyData, 0 ); ++ } ++ ++ FIXME( "unsupported key type %s\n", debugstr_w(type) ); ++ return STATUS_INVALID_PARAMETER; ++} ++ ++NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE encrypt_key, LPCWSTR type, ++ UCHAR *output, ULONG output_len, ULONG *size, ULONG flags ) ++{ ++ struct key *key = export_key; ++ ULONG secret_len; ++ NTSTATUS status; ++ UCHAR *secret; ++ ++ TRACE( "%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags ); ++ ++ if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; ++ if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER; ++ ++ if (encrypt_key) ++ { ++ FIXME( "encryption of key not yet supported\n" ); ++ return STATUS_NOT_IMPLEMENTED; ++ } ++ ++ if ((status = key_get_secret( key, &secret, &secret_len ))) ++ return status; ++ ++ if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB )) ++ { ++ BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output; ++ ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + secret_len; ++ ++ *size = req_size; ++ ++ if (output_len < req_size) ++ return STATUS_BUFFER_TOO_SMALL; ++ ++ key_header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; ++ key_header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; ++ key_header->cbKeyData = secret_len; ++ memcpy( &key_header[1], secret, secret_len ); ++ return STATUS_SUCCESS; ++ } ++ ++ FIXME( "unsupported key type %s\n", debugstr_w(type) ); ++ return STATUS_INVALID_PARAMETER; ++} ++ + NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle ) + { + struct key *key = handle; +diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c +index 9f34a549789..32e25a94a55 100644 +--- a/dlls/bcrypt/tests/bcrypt.c ++++ b/dlls/bcrypt/tests/bcrypt.c +@@ -47,6 +47,9 @@ static NTSTATUS (WINAPI *pBCryptDecrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID + ULONG *, ULONG); + static NTSTATUS (WINAPI *pBCryptDuplicateKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG); + static NTSTATUS (WINAPI *pBCryptDestroyKey)(BCRYPT_KEY_HANDLE); ++static NTSTATUS (WINAPI *pBCryptImportKey)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *, ++ PUCHAR, ULONG, PUCHAR, ULONG, ULONG); ++static NTSTATUS (WINAPI *pBCryptExportKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG); + + static void test_BCryptGenRandom(void) + { +@@ -1540,6 +1543,46 @@ static void test_BCryptDecrypt(void) + ok(ret == STATUS_SUCCESS, "got %08x\n", ret); + } + ++static void test_key_import_export(void) ++{ ++ UCHAR buffer1[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + 16]; ++ UCHAR buffer2[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + 16]; ++ BCRYPT_KEY_DATA_BLOB_HEADER *key_data1 = (void*)buffer1; ++ BCRYPT_ALG_HANDLE aes; ++ BCRYPT_KEY_HANDLE key; ++ NTSTATUS ret; ++ ULONG size; ++ ++ ret = pBCryptOpenAlgorithmProvider(&aes, BCRYPT_AES_ALGORITHM, NULL, 0); ++ ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ++ ++ key_data1->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; ++ key_data1->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; ++ key_data1->cbKeyData = 16; ++ memset(&key_data1[1], 0x11, 16); ++ ++ ret = pBCryptImportKey(aes, NULL, BCRYPT_KEY_DATA_BLOB, &key, NULL, 0, buffer1, sizeof(buffer1), 0); ++ ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ++ ++ size = 0; ++ ret = pBCryptExportKey(key, NULL, BCRYPT_KEY_DATA_BLOB, buffer2, 1, &size, 0); ++ ok(ret == STATUS_BUFFER_TOO_SMALL, "got %08x\n", ret); ++ ok(size == sizeof(buffer2), "Expected sizeof(buffer2), got %u\n", size); ++ ++ size = 0; ++ memset(buffer2, 0xff, sizeof(buffer2)); ++ ret = pBCryptExportKey(key, NULL, BCRYPT_KEY_DATA_BLOB, buffer2, sizeof(buffer2), &size, 0); ++ ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ++ ok(size == sizeof(buffer2), "Expected sizeof(buffer2), got %u\n", size); ++ ok(!memcmp(buffer1, buffer2, sizeof(buffer1)), "Expected exported key to match imported key\n"); ++ ++ ret = pBCryptDestroyKey(key); ++ ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ++ ++ ret = pBCryptCloseAlgorithmProvider(aes, 0); ++ ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ++} ++ + START_TEST(bcrypt) + { + HMODULE module; +@@ -1568,6 +1611,8 @@ START_TEST(bcrypt) + pBCryptDecrypt = (void *)GetProcAddress(module, "BCryptDecrypt"); + pBCryptDuplicateKey = (void *)GetProcAddress(module, "BCryptDuplicateKey"); + pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey"); ++ pBCryptImportKey = (void *)GetProcAddress(module, "BCryptImportKey"); ++ pBCryptExportKey = (void *)GetProcAddress(module, "BCryptExportKey"); + + test_BCryptGenRandom(); + test_BCryptGetFipsAlgorithmMode(); +@@ -1581,6 +1626,7 @@ START_TEST(bcrypt) + test_BCryptGenerateSymmetricKey(); + test_BCryptEncrypt(); + test_BCryptDecrypt(); ++ test_key_import_export(); + + if (pBCryptHash) /* >= Win 10 */ + test_BcryptHash(); +diff --git a/include/bcrypt.h b/include/bcrypt.h +index acf2f30e21c..de812ffe333 100644 +--- a/include/bcrypt.h ++++ b/include/bcrypt.h +@@ -58,6 +58,10 @@ typedef LONG NTSTATUS; + #define BCRYPT_PROVIDER_HANDLE (const WCHAR []){'P','r','o','v','i','d','e','r','H','a','n','d','l','e',0} + #define BCRYPT_SIGNATURE_LENGTH (const WCHAR []){'S','i','g','n','a','t','u','r','e','L','e','n','g','t','h',0} + ++#define BCRYPT_OPAQUE_KEY_BLOB (const WCHAR []){'O','p','a','q','u','e','K','e','y','B','l','o','b',0} ++#define BCRYPT_KEY_DATA_BLOB (const WCHAR []){'K','e','y','D','a','t','a','B','l','o','b',0} ++#define BCRYPT_AES_WRAP_KEY_BLOB (const WCHAR []){'R','f','c','3','5','6','5','K','e','y','W','r','a','p','B','l','o','b',0} ++ + #define MS_PRIMITIVE_PROVIDER (const WCHAR [])\ + {'M','i','c','r','o','s','o','f','t',' ','P','r','i','m','i','t','i','v','e',' ','P','r','o','v','i','d','e','r',0} + #define MS_PLATFORM_CRYPTO_PROVIDER (const WCHAR [])\ +@@ -92,6 +96,13 @@ typedef struct __BCRYPT_KEY_LENGTHS_STRUCT + ULONG dwIncrement; + } BCRYPT_KEY_LENGTHS_STRUCT, BCRYPT_AUTH_TAG_LENGTHS_STRUCT; + ++typedef struct _BCRYPT_KEY_DATA_BLOB_HEADER ++{ ++ ULONG dwMagic; ++ ULONG dwVersion; ++ ULONG cbKeyData; ++} BCRYPT_KEY_DATA_BLOB_HEADER, *PBCRYPT_KEY_DATA_BLOB_HEADER; ++ + typedef struct _BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO + { + ULONG cbSize; +@@ -114,6 +125,9 @@ typedef struct _BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO + #define BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG 0x00000001 + #define BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG 0x00000002 + ++#define BCRYPT_KEY_DATA_BLOB_MAGIC 0x4d42444b ++#define BCRYPT_KEY_DATA_BLOB_VERSION1 1 ++ + typedef PVOID BCRYPT_ALG_HANDLE; + typedef PVOID BCRYPT_KEY_HANDLE; + typedef PVOID BCRYPT_HANDLE; +-- +2.13.1 + diff --git a/patches/bcrypt-Improvements/definition b/patches/bcrypt-Improvements/definition index e72d594c..2fbda0ff 100644 --- a/patches/bcrypt-Improvements/definition +++ b/patches/bcrypt-Improvements/definition @@ -1,2 +1,3 @@ Fixes: [40418] Implement BCrypt AES provider Fixes: [42553] Implement BCrypt ECB chaining mode +Fixes: Implement BCryptImportKey and BCryptExportKey diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 4621b3de..4de3228e 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -3536,6 +3536,7 @@ if test "$enable_bcrypt_Improvements" -eq 1; then patch_apply bcrypt-Improvements/0025-bcrypt-Avoid-crash-in-tests-when-compiling-without-g.patch patch_apply bcrypt-Improvements/0026-bcrypt-Implement-support-for-ECB-chain-mode.patch patch_apply bcrypt-Improvements/0027-bcrypt-Fix-BCryptEncrypt-with-AES_GCM-and-no-input-a.patch + patch_apply bcrypt-Improvements/0028-bcrypt-Partial-implementation-of-BCryptImportKey-and.patch ( printf '%s\n' '+ { "Hans Leidekker", "bcrypt: Add AES provider.", 1 },'; printf '%s\n' '+ { "Michael Müller", "bcrypt: Fix handling of padding when input size equals block size for AES.", 1 },'; @@ -3559,6 +3560,7 @@ if test "$enable_bcrypt_Improvements" -eq 1; then printf '%s\n' '+ { "Sebastian Lackner", "bcrypt: Avoid crash in tests when compiling without gnutls support.", 1 },'; printf '%s\n' '+ { "Sebastian Lackner", "bcrypt: Implement support for ECB chain mode.", 1 },'; printf '%s\n' '+ { "Andrew Wesie", "bcrypt: Fix BCryptEncrypt with AES_GCM and no input and no output.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "bcrypt: Partial implementation of BCryptImportKey and BCryptExportKey.", 1 },'; ) >> "$patchlist" fi