diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec index f00f55c306a..21b54b49348 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 28cf2d8eb28..6e47349de4e 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -768,15 +768,6 @@ NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG se return BCryptDestroyHash( handle ); } -#if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 -static ULONG get_block_size( enum alg_id alg ) -{ - ULONG ret = 0, size = sizeof(ret); - get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size ); - return ret; -} -#endif - #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) struct key { @@ -787,7 +778,55 @@ struct key UCHAR *secret; ULONG secret_len; }; +#elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 +struct key +{ + struct object hdr; + enum alg_id alg_id; + ULONG block_size; + CCCryptorRef ref_encrypt; + CCCryptorRef ref_decrypt; + UCHAR *secret; + ULONG secret_len; +}; +#else +struct key +{ + struct object hdr; + ULONG block_size; +}; +#endif +#if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 +static ULONG get_block_size( enum alg_id alg ) +{ + ULONG ret = 0, size = sizeof(ret); + get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size ); + return ret; +} +static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size ) +{ + if (!strcmpW( 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->secret_len; + + *size = req_size; + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + + header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; + header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; + header->cbKeyData = key->secret_len; + memcpy( &header[1], key->secret, key->secret_len ); + return STATUS_SUCCESS; + } + + FIXME( "unsupported key type %s\n", debugstr_w(type) ); + return STATUS_NOT_IMPLEMENTED; +} +#endif + +#if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len ) { UCHAR *buffer; @@ -898,17 +937,6 @@ static NTSTATUS key_destroy( struct key *key ) return STATUS_SUCCESS; } #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 -struct key -{ - struct object hdr; - enum alg_id alg_id; - ULONG block_size; - CCCryptorRef ref_encrypt; - CCCryptorRef ref_decrypt; - UCHAR *secret; - ULONG secret_len; -}; - static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len ) { UCHAR *buffer; @@ -1006,12 +1034,6 @@ static NTSTATUS key_destroy( struct key *key ) return STATUS_SUCCESS; } #else -struct key -{ - struct object hdr; - ULONG block_size; -}; - static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len ) { ERR( "support for keys not available at build time\n" ); @@ -1043,6 +1065,12 @@ static NTSTATUS key_destroy( struct key *key ) ERR( "support for keys not available at build time\n" ); return STATUS_NOT_IMPLEMENTED; } + +static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size ) +{ + ERR( "support for keys not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} #endif NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle, @@ -1071,6 +1099,69 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_ 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; + } + + return key_export( key, type, output, output_len, size ); +} + 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 b716688f772..6e283487b5d 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -46,6 +46,9 @@ static NTSTATUS (WINAPI *pBCryptEncrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID static NTSTATUS (WINAPI *pBCryptDecrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG, 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) { @@ -821,6 +824,51 @@ 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 || broken(ret == STATUS_INVALID_PARAMETER) /* vista */, "got %08x\n", ret); + if (ret == STATUS_INVALID_PARAMETER) + { + win_skip("broken BCryptImportKey\n"); + return; + } + + 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), "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), "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; @@ -848,6 +896,8 @@ START_TEST(bcrypt) pBCryptEncrypt = (void *)GetProcAddress(module, "BCryptEncrypt"); pBCryptDecrypt = (void *)GetProcAddress(module, "BCryptDecrypt"); pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey"); + pBCryptImportKey = (void *)GetProcAddress(module, "BCryptImportKey"); + pBCryptExportKey = (void *)GetProcAddress(module, "BCryptExportKey"); test_BCryptGenRandom(); test_BCryptGetFipsAlgorithmMode(); @@ -857,6 +907,7 @@ START_TEST(bcrypt) test_BCryptGenerateSymmetricKey(); test_BCryptEncrypt(); test_BCryptDecrypt(); + test_key_import_export(); if (pBCryptHash) /* >= Win 10 */ test_BcryptHash(); diff --git a/dlls/ncrypt/ncrypt.spec b/dlls/ncrypt/ncrypt.spec index 5d371210d9e..5d5fae0b5cb 100644 --- a/dlls/ncrypt/ncrypt.spec +++ b/dlls/ncrypt/ncrypt.spec @@ -22,7 +22,7 @@ @ stub BCryptEnumContexts @ stub BCryptEnumProviders @ stub BCryptEnumRegisteredProviders -@ stub BCryptExportKey +@ stdcall BCryptExportKey(ptr ptr wstr ptr long ptr long) bcrypt.BCryptExportKey @ stub BCryptFinalizeKeyPair @ stdcall BCryptFinishHash(ptr ptr long long) bcrypt.BCryptFinishHash @ stub BCryptFreeBuffer @@ -33,7 +33,7 @@ @ stdcall BCryptGetProperty(ptr wstr ptr long ptr long) bcrypt.BCryptGetProperty @ stdcall BCryptHash(ptr ptr long ptr long ptr long) bcrypt.BCryptHash @ stdcall BCryptHashData(ptr ptr long long) bcrypt.BCryptHashData -@ stub BCryptImportKey +@ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) bcrypt.BCryptImportKey @ stub BCryptImportKeyPair @ stub BCryptKeyDerivation @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) bcrypt.BCryptOpenAlgorithmProvider diff --git a/include/bcrypt.h b/include/bcrypt.h index 1f7093c25a3..1be9b8533ec 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 [])\ @@ -117,6 +121,16 @@ typedef struct _CRYPT_PROVIDER_REG PCRYPT_IMAGE_REG pKM; } CRYPT_PROVIDER_REG, *PCRYPT_PROVIDER_REG; +typedef struct _BCRYPT_KEY_DATA_BLOB_HEADER +{ + ULONG dwMagic; + ULONG dwVersion; + ULONG cbKeyData; +} BCRYPT_KEY_DATA_BLOB_HEADER, *PBCRYPT_KEY_DATA_BLOB_HEADER; + +#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;