Partial implementation of BCryptImportKey and BCryptExportKey in bcrypt Accepted

Revisions: 

Revision 1

user image Michael Müller Author
13 Aug. 17

Implements the case of simple unencrypted key blobs.

user image Michael Müller Author
13 Aug. 17

A user on IRC reported that the compilation fails with this patch applied if gnutls is not available. We should add the following fields to the dummy key structure to fix the issue:

UCHAR *secret; ULONG secret_len;

Single files Merged diff Tar archive
You have unsaved changes. Press CTRL + ENTER in a text field to submit your comments.

0001-bcrypt-Partial-implementation-of-BCryptImportKey-and.patch

From 079826c92feb9fdbcb015f2c9aa3dbda5449d3a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
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 | 81 ++++++++++++++++++++++++++++++++++++++++++++++
dlls/bcrypt/tests/bcrypt.c | 46 ++++++++++++++++++++++++++
include/bcrypt.h | 14 ++++++++
4 files changed, 143 insertions(+), 2 deletions(-)
diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec
index f5911d2cd4..f8a8c45a1d 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 d269083eca..9fb965fea5 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -1140,6 +1140,87 @@ 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, PUCHAR object, ULONG object_len, PUCHAR 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_NO_MEMORY;
+ }
+
+ 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: %d\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,
+ PUCHAR output, ULONG output_len, ULONG *size, ULONG flags)
+{
+ struct key *key = export_key;
+
+ 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_NO_MEMORY;
+ }
+
+ 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) + key->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 = key->secret_len;
+ memcpy(&key_header[1], key->secret, key->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 9f34a54978..0795a54445 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 size %u, got %u\n", sizeof(buffer2), 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 size %u, got %u\n", sizeof(buffer2), 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 acf2f30e21..de812ffe33 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.2