Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/bcrypt/tests/bcrypt.c | 72 ++++++++++++++++++++++++++++++++++---- include/bcrypt.h | 12 +++++++ 2 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 198acbf721..5cfcbc29ab 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -62,6 +62,9 @@ static NTSTATUS (WINAPI *pBCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE *, LPCW static NTSTATUS (WINAPI *pBCryptSetProperty)(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG); static NTSTATUS (WINAPI *pBCryptSignHash)(BCRYPT_KEY_HANDLE, void *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG *, ULONG); static NTSTATUS (WINAPI *pBCryptVerifySignature)(BCRYPT_KEY_HANDLE, VOID *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG); +static NTSTATUS (WINAPI *pBCryptSecretAgreement)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE, BCRYPT_SECRET_HANDLE *, ULONG); +static NTSTATUS (WINAPI *pBCryptDestroySecret)(BCRYPT_SECRET_HANDLE); +static NTSTATUS (WINAPI *pBCryptDeriveKey)(BCRYPT_SECRET_HANDLE, LPCWSTR, BCryptBufferDesc *, PUCHAR, ULONG, ULONG *, ULONG);
static void test_BCryptGenRandom(void) { @@ -1923,13 +1926,30 @@ static void test_RSA_SIGN(void)
static BYTE eccprivkey[] = { - 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, 0xfb, 0xbd, 0x3d, 0x20, 0x1b, 0x6d, 0x66, 0xb3, - 0x7c, 0x9f, 0x89, 0xf3, 0xe4, 0x41, 0x16, 0xa5, 0x68, 0x52, 0x77, 0xac, 0xab, 0x55, 0xb2, 0x6c, - 0xb0, 0x23, 0x55, 0xcb, 0x96, 0x14, 0xfd, 0x0b, 0x1c, 0xef, 0xdf, 0x07, 0x6d, 0x31, 0xaf, 0x39, - 0xce, 0x8c, 0x8f, 0x9d, 0x75, 0xd0, 0x7b, 0xea, 0x81, 0xdc, 0x40, 0x21, 0x1f, 0x58, 0x22, 0x5f, - 0x72, 0x55, 0xfc, 0x58, 0x8a, 0xeb, 0x88, 0x5d, 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe, - 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86, - 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd + 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, + 0x0b, 0x3b, 0x35, 0x26, 0x8c, 0xdd, 0x98, 0x8a, 0xe2, 0x1d, 0xc0, 0x95, 0x8e, 0x3a, 0x87, 0xc8, + 0x3e, 0xbb, 0xe9, 0xfd, 0xfa, 0xc2, 0x87, 0x82, 0xc4, 0x20, 0xd5, 0x8f, 0xde, 0x0b, 0x4f, 0xdb, + 0xae, 0x94, 0x8e, 0xb3, 0x65, 0x1b, 0x76, 0xdd, 0x16, 0x98, 0x2b, 0x90, 0x3c, 0x9a, 0xbd, 0x32, + 0x6d, 0x4f, 0x92, 0x3c, 0xd9, 0x68, 0xc1, 0xd1, 0xd3, 0x50, 0xa4, 0xc5, 0x50, 0xa0, 0x92, 0x8b, + 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe, 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, + 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86, 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd +}; + + +static BYTE ecdh_pubkey[] = +{ + 0x45, 0x43, 0x4b, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x07, 0x61, 0x9d, 0x49, 0x63, 0x6b, 0x96, 0x94, 0xd1, 0x8f, 0xd1, 0x48, 0xcc, 0xcf, 0x72, 0x4d, + 0xff, 0x43, 0xf4, 0x97, 0x0f, 0xa3, 0x8a, 0x72, 0xe9, 0xe0, 0xba, 0x87, 0x6d, 0xc3, 0x62, 0x15, + 0xae, 0x65, 0xdd, 0x31, 0x51, 0xfc, 0x3b, 0xc9, 0x59, 0xa1, 0x0a, 0x92, 0x17, 0x2b, 0x64, 0x55, + 0x03, 0x3e, 0x62, 0x1d, 0xac, 0x3e, 0x37, 0x40, 0x6a, 0x4c, 0xb6, 0x21, 0x3f, 0x73, 0x5c, 0xf5 +}; + +/* little endian */ +static BYTE ecdh_secret[] = +{ + 0x48, 0xb0, 0x11, 0xdb, 0x69, 0x4e, 0xb4, 0xf4, 0xf5, 0x3e, 0xe1, 0x9b, 0xca, 0x00, 0x04, 0xc8, + 0x9b, 0x69, 0xaf, 0xd1, 0xaf, 0x1f, 0xc2, 0xd7, 0x83, 0x0a, 0xb7, 0xf8, 0x4f, 0x24, 0x32, 0x8e, };
static void test_ECDH(void) @@ -1938,6 +1958,7 @@ static void test_ECDH(void) BCRYPT_ECCKEY_BLOB *ecckey; BCRYPT_ALG_HANDLE alg; BCRYPT_KEY_HANDLE key, privkey, pubkey; + BCRYPT_SECRET_HANDLE secret; NTSTATUS status; ULONG size;
@@ -2008,6 +2029,40 @@ static void test_ECDH(void) ok(!memcmp(buf, eccprivkey, size), "wrong data\n"); HeapFree(GetProcessHeap(), 0, buf);
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubkey, ecdh_pubkey, sizeof(ecdh_pubkey), 0); + ok(status == STATUS_SUCCESS, "got %08x\n", status); + + status = pBCryptSecretAgreement(privkey, pubkey, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08x\n", status); + + if (status == STATUS_SUCCESS) + { + /* verify result on windows 10 */ + status = pBCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &size, 0); + + if (status == STATUS_NOT_SUPPORTED) + { + win_skip("BCRYPT_KDF_RAW_SECRET not supported\n"); + goto over; + } + + todo_wine ok(status == STATUS_SUCCESS, "got %08x\n", status); + + if (status == STATUS_SUCCESS) + { + ok (size, "size not set\n"); + buf = HeapAlloc(GetProcessHeap(), 0, size); + status = pBCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %08x\n", status); + ok(size == 32, "size of secret key incorrect, got %u, expected 32\n", size); + ok(!(memcmp(ecdh_secret, buf, size)), "wrong data\n"); + HeapFree(GetProcessHeap(), 0, buf); + } + } + + over: + pBCryptDestroySecret(secret); + pBCryptDestroyKey(pubkey); pBCryptDestroyKey(privkey); pBCryptCloseAlgorithmProvider(alg, 0); } @@ -2284,6 +2339,9 @@ START_TEST(bcrypt) pBCryptSetProperty = (void *)GetProcAddress(module, "BCryptSetProperty"); pBCryptSignHash = (void *)GetProcAddress(module, "BCryptSignHash"); pBCryptVerifySignature = (void *)GetProcAddress(module, "BCryptVerifySignature"); + pBCryptSecretAgreement = (void *)GetProcAddress(module, "BCryptSecretAgreement"); + pBCryptDestroySecret = (void *)GetProcAddress(module, "BCryptDestroySecret"); + pBCryptDeriveKey = (void *)GetProcAddress(module, "BCryptDeriveKey");
test_BCryptGenRandom(); test_BCryptGetFipsAlgorithmMode(); diff --git a/include/bcrypt.h b/include/bcrypt.h index 4546aea394..f393dc6e5c 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -92,6 +92,12 @@ typedef LONG NTSTATUS; #define BCRYPT_CHAIN_MODE_CFB L"ChainingModeCFB" #define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM" #define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM" + +#define BCRYPT_KDF_HASH L"HASH" +#define BCRYPT_KDF_HMAC L"HMAC" +#define BCRYPT_KDF_TLS_PRF L"TLS_PRF" +#define BCRYPT_KDF_SP80056A_CONCAT L"SP800_56A_CONCAT" +#define BCRYPT_KDF_RAW_SECRET L"TRUNCATE" #else static const WCHAR BCRYPT_ALGORITHM_NAME[] = {'A','l','g','o','r','i','t','h','m','N','a','m','e',0}; static const WCHAR BCRYPT_AUTH_TAG_LENGTH[] = {'A','u','t','h','T','a','g','L','e','n','g','t','h',0}; @@ -146,6 +152,12 @@ static const WCHAR BCRYPT_CHAIN_MODE_ECB[] = {'C','h','a','i','n','i','n','g','M static const WCHAR BCRYPT_CHAIN_MODE_CFB[] = {'C','h','a','i','n','i','n','g','M','o','d','e','C','F','B',0}; static const WCHAR BCRYPT_CHAIN_MODE_CCM[] = {'C','h','a','i','n','i','n','g','M','o','d','e','C','C','M',0}; static const WCHAR BCRYPT_CHAIN_MODE_GCM[] = {'C','h','a','i','n','i','n','g','M','o','d','e','G','C','M',0}; + +static const WCHAR BCRYPT_KDF_HASH[] = {'H','A','S','H',0}; +static const WCHAR BCRYPT_KDF_HMAC[] = {'H','M','A','C',0}; +static const WCHAR BCRYPT_KDF_TLS_PRF[] = {'T','L','S','_','P','R','F',0}; +static const WCHAR BCRYPT_KDF_SP80056A_CONCAT[] = {'S','P','8','0','0','_','5','6','A','_','C','O','N','C','A','T',0}; +static const WCHAR BCRYPT_KDF_RAW_SECRET[] = {'T','R','U','N','C','A','T','E',0}; #endif
#define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- configure.ac | 14 ++ dlls/bcrypt/Makefile.in | 1 + dlls/bcrypt/bcrypt_internal.h | 13 ++ dlls/bcrypt/bcrypt_main.c | 75 ++++++++-- dlls/bcrypt/gcrypt.c | 263 ++++++++++++++++++++++++++++++++++ dlls/bcrypt/gnutls.c | 9 ++ dlls/bcrypt/tests/bcrypt.c | 2 +- 7 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 dlls/bcrypt/gcrypt.c
diff --git a/configure.ac b/configure.ac index 5e36331596..e4a6e85af8 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,7 @@ AC_ARG_WITH(faudio, AS_HELP_STRING([--without-faudio],[do not use FAudio (XAu AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms])) AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) +AC_ARG_WITH(gcrypt, AS_HELP_STRING([--without-gcrypt],[do not use libgcrypt])) AC_ARG_WITH(gettext, AS_HELP_STRING([--without-gettext],[do not use gettext])) AC_ARG_WITH(gettextpo, AS_HELP_STRING([--with-gettextpo],[use the GetTextPO library to rebuild po files]), [if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi]) @@ -1996,6 +1997,19 @@ WINE_NOTICE_WITH(vkd3d,[test "x$ac_cv_lib_soname_vkd3d" = "x"], [vkd3d ${notice_platform}development files not found (or too old), Direct3D 12 won't be supported.]) test "x$ac_cv_lib_soname_vkd3d" != "x" || enable_d3d12=${enable_d3d12:-no}
+dnl **** Check for gcrypt **** +if test "x$with_gcrypt" != "xno" +then + WINE_PACKAGE_FLAGS(GCRYPT,[libgcrypt],,,, + [AC_CHECK_HEADERS([gcrypt.h]) + if test "$ac_cv_header_gcrypt_h" = "yes" + then + WINE_CHECK_SONAME(gcrypt,gcry_sexp_build,,,[$GCRYPT_LIBS]) + fi]) +fi +WINE_NOTICE_WITH(gcrypt,[test "x$ac_cv_lib_soname_gcrypt" = "x"], + [libgcrypt ${notice_platform}development files not found, GCRYPT won't be supported.]) + dnl **** Check for gcc specific options ****
AC_SUBST(EXTRACFLAGS,"") diff --git a/dlls/bcrypt/Makefile.in b/dlls/bcrypt/Makefile.in index dd6d4a7664..ea3486a400 100644 --- a/dlls/bcrypt/Makefile.in +++ b/dlls/bcrypt/Makefile.in @@ -5,6 +5,7 @@ EXTRAINCL = $(GNUTLS_CFLAGS)
C_SRCS = \ bcrypt_main.c \ + gcrypt.c \ gnutls.c \ macos.c \ md2.c \ diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index d026dab729..09e675a655 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -25,6 +25,9 @@ #include <gnutls/gnutls.h> #include <gnutls/crypto.h> #include <gnutls/abstract.h> +#ifdef SONAME_LIBGCRYPT +#include <gcrypt.h> +#endif #elif HAVE_COMMONCRYPTO_COMMONCRYPTOR_H #include <AvailabilityMacros.h> #include <CommonCrypto/CommonCryptor.h> @@ -157,6 +160,12 @@ struct algorithm BOOL hmac; };
+struct secret +{ + UCHAR *data; + ULONG len; +}; + #if defined(HAVE_GNUTLS_CIPHER_INIT) struct key_symmetric { @@ -251,6 +260,7 @@ NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN; BOOL key_is_symmetric( struct key * ) DECLSPEC_HIDDEN; NTSTATUS key_export_ecc( struct key *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN; NTSTATUS key_import_ecc( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN; +NTSTATUS compute_secret_ecc (struct key *pubkey_in, struct key *privkey_in, struct secret *secret) DECLSPEC_HIDDEN;
BOOL is_zero_vector( const UCHAR *, ULONG ) DECLSPEC_HIDDEN; BOOL is_equal_vector( const UCHAR *, ULONG, const UCHAR *, ULONG ) DECLSPEC_HIDDEN; @@ -258,4 +268,7 @@ BOOL is_equal_vector( const UCHAR *, ULONG, const UCHAR *, ULONG ) DECLSPEC_HIDD BOOL gnutls_initialize(void) DECLSPEC_HIDDEN; void gnutls_uninitialize(void) DECLSPEC_HIDDEN;
+BOOL gcrypt_initialize(void) DECLSPEC_HIDDEN; +void gcrypt_uninitialize(void) DECLSPEC_HIDDEN; + #endif /* __BCRYPT_INTERNAL_H */ diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 2ac36d3db0..ed64cd1965 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1331,6 +1331,12 @@ NTSTATUS key_import_ecc( struct key *key, UCHAR *input, ULONG len ) ERR( "support for keys not available at build time\n" ); return STATUS_NOT_IMPLEMENTED; } + +NTSTATUS compute_secret_ecc (struct key *pubkey_in, struct key *privkey_in, struct secret *secret) +{ + ERR( "support for secrets not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} #endif
NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle, @@ -1696,27 +1702,70 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO return STATUS_SUCCESS; }
-NTSTATUS WINAPI BCryptSecretAgreement(BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE key, BCRYPT_SECRET_HANDLE *secret, ULONG flags) +NTSTATUS WINAPI BCryptSecretAgreement(BCRYPT_KEY_HANDLE hPrivKey, BCRYPT_KEY_HANDLE hPubKey, BCRYPT_SECRET_HANDLE *secret_out, ULONG flags) { - FIXME( "%p, %p, %p, %08x\n", handle, key, secret, flags ); + struct key *privkey = hPrivKey; + struct key *pubkey = hPubKey; + struct secret *secret; + NTSTATUS status;
- if(secret) - *secret = (BCRYPT_SECRET_HANDLE *)0xDEADFEED; + TRACE( "%p, %p, %p, %08x\n", hPrivKey, hPubKey, secret_out, flags );
- return STATUS_SUCCESS; + secret = heap_alloc( sizeof(*secret) ); + + if ((status = compute_secret_ecc(privkey, pubkey, secret))) + { + heap_free(secret); + } + else + { + *secret_out = secret; + } + + return status; }
-NTSTATUS WINAPI BCryptDestroySecret(BCRYPT_SECRET_HANDLE secret) +NTSTATUS WINAPI BCryptDestroySecret(BCRYPT_SECRET_HANDLE hSecret) { - FIXME( "%p\n", secret ); + struct secret *secret = hSecret; + + TRACE( "%p\n", hSecret ); + + heap_free(secret->data); + heap_free(secret); + return STATUS_SUCCESS; }
-NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE secret, LPCWSTR kdf, BCryptBufferDesc *parameter, +NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE hSecret, LPCWSTR deriv_func, BCryptBufferDesc *parameter, PUCHAR derived, ULONG derived_size, ULONG *result, ULONG flags) { - FIXME( "%p, %s, %p, %p, %d, %p, %08x\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags ); - return STATUS_INTERNAL_ERROR; + struct secret *secret = hSecret; + + TRACE( "%p, %s, %p, %p, %d, %p, %08x\n", secret, debugstr_w(deriv_func), parameter, derived, derived_size, result, flags ); + + if (!(strcmpW(deriv_func, BCRYPT_KDF_RAW_SECRET))) + { + ULONG n; + ULONG secret_length = secret->len; + + if (!derived) + { + *result = secret_length; + return STATUS_SUCCESS; + } + + /* outputs in little endian for some reason */ + for (n = 0; n < secret_length && n < derived_size; n++) + { + derived[n] = secret->data[secret_length - n - 1]; + } + + *result = n; + return STATUS_SUCCESS; + } + FIXME( "Derivation function %s not supported.\n", debugstr_w(deriv_func) ); + return STATUS_NOT_IMPLEMENTED; }
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) @@ -1728,6 +1777,9 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) DisableThreadLibraryCalls( hinst ); #ifdef HAVE_GNUTLS_CIPHER_INIT gnutls_initialize(); +#ifdef SONAME_LIBGCRYPT + gcrypt_initialize(); +#endif #endif break;
@@ -1735,6 +1787,9 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) if (reserved) break; #ifdef HAVE_GNUTLS_CIPHER_INIT gnutls_uninitialize(); +#ifdef SONAME_LIBGCRYPT + gcrypt_uninitialize(); +#endif #endif break; } diff --git a/dlls/bcrypt/gcrypt.c b/dlls/bcrypt/gcrypt.c new file mode 100644 index 0000000000..9a3b164f61 --- /dev/null +++ b/dlls/bcrypt/gcrypt.c @@ -0,0 +1,263 @@ +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#ifdef HAVE_GNUTLS_CIPHER_INIT +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> +#include <gnutls/abstract.h> +#ifdef HAVE_LIBGCRYPT +#include <libgcrypt/libgcrypt.h> +#endif +#endif + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "bcrypt.h" + +#include "bcrypt_internal.h" + +#include "wine/debug.h" +#include "wine/heap.h" +#include "wine/library.h" +#include "wine/unicode.h" + +#if defined(HAVE_GNUTLS_CIPHER_INIT) && defined(SONAME_LIBGCRYPT) +WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +static void *libgcrypt_handle; +#define MAKE_FUNCPTR(f) static typeof(f) * p##f +MAKE_FUNCPTR(gcry_sexp_build); +MAKE_FUNCPTR(gcry_pk_encrypt); +MAKE_FUNCPTR(gcry_sexp_extract_param); +MAKE_FUNCPTR(gcry_mpi_point_new); +MAKE_FUNCPTR(gcry_mpi_ec_decode_point); +MAKE_FUNCPTR(gcry_mpi_new); +MAKE_FUNCPTR(gcry_mpi_point_snatch_get); +MAKE_FUNCPTR(gcry_mpi_print); +MAKE_FUNCPTR(gcry_sexp_release); +MAKE_FUNCPTR(gcry_mpi_release); +MAKE_FUNCPTR(gcry_mpi_point_release); +MAKE_FUNCPTR(gcry_strsource); +MAKE_FUNCPTR(gcry_strerror); +#undef MAKE_FUNCPTR + +BOOL gcrypt_initialize(void) +{ + if (!(libgcrypt_handle = wine_dlopen( SONAME_LIBGCRYPT, RTLD_NOW, NULL, 0 ))) + { + ERR_(winediag)( "failed to load libgcrypt, no support for diffie hellman key exchange\n" ); + return FALSE; + } + +#define LOAD_FUNCPTR(f) \ + if (!(p##f = wine_dlsym( libgcrypt_handle, #f, NULL, 0 ))) \ + { \ + ERR( "failed to load %s\n", #f ); \ + goto fail; \ + } + + LOAD_FUNCPTR(gcry_sexp_build); + LOAD_FUNCPTR(gcry_pk_encrypt); + LOAD_FUNCPTR(gcry_sexp_extract_param); + LOAD_FUNCPTR(gcry_mpi_point_new); + LOAD_FUNCPTR(gcry_mpi_ec_decode_point); + LOAD_FUNCPTR(gcry_mpi_new); + LOAD_FUNCPTR(gcry_mpi_point_snatch_get); + LOAD_FUNCPTR(gcry_mpi_print); + LOAD_FUNCPTR(gcry_sexp_release); + LOAD_FUNCPTR(gcry_mpi_release); + LOAD_FUNCPTR(gcry_mpi_point_release); + LOAD_FUNCPTR(gcry_strsource); + LOAD_FUNCPTR(gcry_strerror); +#undef LOAD_FUNCPTR + + return TRUE; + +fail: + wine_dlclose( libgcrypt_handle, NULL, 0 ); + libgcrypt_handle = NULL; + return FALSE; +} + + +void gcrypt_uninitialize(void) +{ + wine_dlclose( libgcrypt_handle, NULL, 0 ); + libgcrypt_handle = NULL; +} + +/* this is necessary since GNUTLS doesn't support ECDH public key encryption, maybe we can replace this when it does: + https://github.com/gnutls/gnutls/blob/cdc4fc288d87f91f974aa23b6e8595a53970ce... */ +NTSTATUS compute_secret_ecc (struct key *privkey_in, struct key *pubkey_in, struct secret *secret) +{ + const char *pubkey_format; + DWORD key_size; + gcry_sexp_t pubkey = NULL; + gcry_sexp_t privkey = NULL; + gcry_sexp_t xchg_result = NULL; + gcry_mpi_t result_mpi = NULL; + gcry_mpi_point_t result_point = NULL; + gcry_mpi_t secret_key = NULL; + gcry_error_t err; + NTSTATUS status = STATUS_SUCCESS; + + switch (pubkey_in->alg_id) + { + case ALG_ID_ECDH_P256: + pubkey_format = "NIST P-256"; + key_size = 32; + break; + default: + FIXME("Unsupported algorithm id: %u\n", pubkey_in->alg_id); + return STATUS_INTERNAL_ERROR; + } + + /* import public key - + copy public key into temporary buffer so we can prepend 0x04 (to indicate it is uncompressed) */ + { + UCHAR *public_key_raw = heap_alloc((key_size * 2) + 1); + public_key_raw[0] = 0x04; + memcpy(public_key_raw + 1, pubkey_in->u.a.pubkey + sizeof(BCRYPT_ECCKEY_BLOB), key_size * 2); + + err = pgcry_sexp_build(&pubkey, NULL, + "(key-data(public-key(ecdh(curve %s)(q %b))))", + pubkey_format, + (key_size * 2) + 1, + public_key_raw); + + heap_free(public_key_raw); + } + + if (err) + { + ERR("Failed to build gcrypt public key\n"); + goto done; + } + + /* import private key */ + /* extract private key from blob structure */ + { + UCHAR *private_key_raw = heap_alloc(key_size); + UCHAR *key_blob; + ULONG blob_size; + + status = key_export_ecc( privkey_in, NULL, 0, &blob_size ); + if (status) + goto done; + + key_blob = heap_alloc(blob_size); + status = key_export_ecc( privkey_in, key_blob, blob_size, &blob_size); + if (status) + { + heap_free(private_key_raw); + heap_free(key_blob); + goto done; + } + + memcpy(private_key_raw, key_blob + sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 2, key_size); + heap_free(key_blob); + + err = pgcry_sexp_build(&privkey, NULL, + "(data(flags raw)(value %b))", + key_size, + private_key_raw); + + heap_free(private_key_raw); + } + + if (err) + { + ERR("Failed to build gcrypt private key data\n"); + goto done; + } + + if ((err = pgcry_pk_encrypt(&xchg_result, privkey, pubkey))) + { + ERR("Failed to perform key exchange\n"); + goto done; + } + + if ((err = pgcry_sexp_extract_param(xchg_result, "", "s", &result_mpi, NULL))) + { + ERR("Failed to extract result of key exchange\n"); + goto done; + } + + result_point = pgcry_mpi_point_new(0); + + if ((err = pgcry_mpi_ec_decode_point(result_point, result_mpi, NULL))) + { + ERR("Failed decoding point from result\n"); + goto done; + } + + secret_key = pgcry_mpi_new(0); + if (!secret_key) + { + status = STATUS_NO_MEMORY; + goto done; + } + + /* releases result_point, (we don't need to free it later) */ + pgcry_mpi_point_snatch_get(secret_key, NULL, NULL, result_point); + + { + size_t secret_size; + UCHAR *tmp_buffer; + + if ((err = pgcry_mpi_print(GCRYMPI_FMT_STD, NULL, 0, &secret_size, secret_key))) + { + goto done; + } + + if (secret_size != key_size && secret_size != key_size + 1) + { + ERR("got secret size %lu, expected %u\n", secret_size, key_size); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + tmp_buffer = heap_alloc(secret_size); + if ((err = pgcry_mpi_print(GCRYMPI_FMT_STD, tmp_buffer, secret_size, NULL, secret_key))) + { + goto done; + } + + if (secret_size % 2 != 0) /* remove prepended 0 */ + { + UCHAR *secret_buffer = heap_alloc(secret_size - 1); + memcpy(secret_buffer, tmp_buffer + 1, secret_size - 1); + heap_free(tmp_buffer); + secret->data = secret_buffer; + secret->len = secret_size - 1; + } + else + { + secret->data = tmp_buffer; + secret->len = secret_size; + } + } + + done: + pgcry_sexp_release(pubkey); + pgcry_sexp_release(privkey); + pgcry_sexp_release(xchg_result); + pgcry_mpi_release(result_mpi); + pgcry_mpi_release(secret_key); + + if (status) + { + return status; + } + if (err) + { + ERR("Error = %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); + return STATUS_INTERNAL_ERROR; + } + return STATUS_SUCCESS; +} +#endif diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 868f898bbb..f62669982c 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1297,4 +1297,13 @@ NTSTATUS key_destroy( struct key *key ) heap_free( key ); return STATUS_SUCCESS; } + +#ifndef SONAME_LIBGCRYPT +NTSTATUS compute_secret_ecc (struct key *pubkey_in, struct key *privkey_in, struct secret *secret) +{ + ERR("support for secrets not available without gcrypt"); + return STATUS_NOT_IMPLEMENTED; +} +#endif + #endif diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 5cfcbc29ab..39fd36ab92 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2046,7 +2046,7 @@ static void test_ECDH(void) goto over; }
- todo_wine ok(status == STATUS_SUCCESS, "got %08x\n", status); + ok(status == STATUS_SUCCESS, "got %08x\n", status);
if (status == STATUS_SUCCESS) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=62979
Your paranoid android.
=== wvistau64 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w2008s64 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w7u (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w8 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w8adm (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w864 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== wvistau64 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w2008s64 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w864 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== debian10 (32 bit report) ===
bcrypt: bcrypt.c:2036: Test failed: got c0000002
=== debian10 (32 bit French report) ===
bcrypt: bcrypt.c:2036: Test failed: got c0000002
=== debian10 (32 bit Japanese:Japan report) ===
bcrypt: bcrypt.c:2036: Test failed: got c0000002
=== debian10 (32 bit Chinese:China report) ===
bcrypt: bcrypt.c:2036: Test failed: got c0000002
=== debian10 (32 bit WoW report) ===
bcrypt: bcrypt.c:2036: Test failed: got c0000002
=== debian10 (64 bit WoW report) ===
bcrypt: bcrypt.c:2036: Test failed: got c0000002
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=62978
Your paranoid android.
=== wvistau64 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w2008s64 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w7u (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w8 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w8adm (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w864 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== wvistau64 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w2008s64 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w864 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
On 2020-01-07 10:14, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=62978
Your paranoid android.
=== wvistau64 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w2008s64 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w7u (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w8 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w8adm (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w864 (32 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== wvistau64 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w2008s64 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
=== w864 (64 bit report) ===
bcrypt: bcrypt.c:2018: Test failed: got c0000001 bcrypt.c:2022: Test failed: got c0000008 bcrypt.c:2023: Test failed: size not set bcrypt.c:2027: Test failed: got c0000008 bcrypt.c:2028: Test failed: got 0 bcrypt.c:2036: Test failed: got c0000008
Whoops, looks like a made a copy-paste mistake, not sure why that didn't fail on windows 10 (which I ran the test on).
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v2: Fixed a copy-paste error. --- dlls/bcrypt/tests/bcrypt.c | 71 ++++++++++++++++++++++++++++++++++---- include/bcrypt.h | 12 +++++++ 2 files changed, 76 insertions(+), 7 deletions(-)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 198acbf721..08f13bdbfa 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -62,6 +62,9 @@ static NTSTATUS (WINAPI *pBCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE *, LPCW static NTSTATUS (WINAPI *pBCryptSetProperty)(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG); static NTSTATUS (WINAPI *pBCryptSignHash)(BCRYPT_KEY_HANDLE, void *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG *, ULONG); static NTSTATUS (WINAPI *pBCryptVerifySignature)(BCRYPT_KEY_HANDLE, VOID *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG); +static NTSTATUS (WINAPI *pBCryptSecretAgreement)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE, BCRYPT_SECRET_HANDLE *, ULONG); +static NTSTATUS (WINAPI *pBCryptDestroySecret)(BCRYPT_SECRET_HANDLE); +static NTSTATUS (WINAPI *pBCryptDeriveKey)(BCRYPT_SECRET_HANDLE, LPCWSTR, BCryptBufferDesc *, PUCHAR, ULONG, ULONG *, ULONG);
static void test_BCryptGenRandom(void) { @@ -1923,13 +1926,29 @@ static void test_RSA_SIGN(void)
static BYTE eccprivkey[] = { - 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, 0xfb, 0xbd, 0x3d, 0x20, 0x1b, 0x6d, 0x66, 0xb3, - 0x7c, 0x9f, 0x89, 0xf3, 0xe4, 0x41, 0x16, 0xa5, 0x68, 0x52, 0x77, 0xac, 0xab, 0x55, 0xb2, 0x6c, - 0xb0, 0x23, 0x55, 0xcb, 0x96, 0x14, 0xfd, 0x0b, 0x1c, 0xef, 0xdf, 0x07, 0x6d, 0x31, 0xaf, 0x39, - 0xce, 0x8c, 0x8f, 0x9d, 0x75, 0xd0, 0x7b, 0xea, 0x81, 0xdc, 0x40, 0x21, 0x1f, 0x58, 0x22, 0x5f, - 0x72, 0x55, 0xfc, 0x58, 0x8a, 0xeb, 0x88, 0x5d, 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe, - 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86, - 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd + 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, + 0xfb, 0xbd, 0x3d, 0x20, 0x1b, 0x6d, 0x66, 0xb3, 0x7c, 0x9f, 0x89, 0xf3, 0xe4, 0x41, 0x16, 0xa5, + 0x68, 0x52, 0x77, 0xac, 0xab, 0x55, 0xb2, 0x6c, 0xb0, 0x23, 0x55, 0xcb, 0x96, 0x14, 0xfd, 0x0b, + 0x1c, 0xef, 0xdf, 0x07, 0x6d, 0x31, 0xaf, 0x39, 0xce, 0x8c, 0x8f, 0x9d, 0x75, 0xd0, 0x7b, 0xea, + 0x81, 0xdc, 0x40, 0x21, 0x1f, 0x58, 0x22, 0x5f, 0x72, 0x55, 0xfc, 0x58, 0x8a, 0xeb, 0x88, 0x5d, + 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe, 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, + 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86, 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd +}; + +static BYTE ecdh_pubkey[] = +{ + 0x45, 0x43, 0x4b, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x07, 0x61, 0x9d, 0x49, 0x63, 0x6b, 0x96, 0x94, 0xd1, 0x8f, 0xd1, 0x48, 0xcc, 0xcf, 0x72, 0x4d, + 0xff, 0x43, 0xf4, 0x97, 0x0f, 0xa3, 0x8a, 0x72, 0xe9, 0xe0, 0xba, 0x87, 0x6d, 0xc3, 0x62, 0x15, + 0xae, 0x65, 0xdd, 0x31, 0x51, 0xfc, 0x3b, 0xc9, 0x59, 0xa1, 0x0a, 0x92, 0x17, 0x2b, 0x64, 0x55, + 0x03, 0x3e, 0x62, 0x1d, 0xac, 0x3e, 0x37, 0x40, 0x6a, 0x4c, 0xb6, 0x21, 0x3f, 0x73, 0x5c, 0xf5 +}; + +/* little endian */ +static BYTE ecdh_secret[] = +{ + 0x48, 0xb0, 0x11, 0xdb, 0x69, 0x4e, 0xb4, 0xf4, 0xf5, 0x3e, 0xe1, 0x9b, 0xca, 0x00, 0x04, 0xc8, + 0x9b, 0x69, 0xaf, 0xd1, 0xaf, 0x1f, 0xc2, 0xd7, 0x83, 0x0a, 0xb7, 0xf8, 0x4f, 0x24, 0x32, 0x8e, };
static void test_ECDH(void) @@ -1938,6 +1957,7 @@ static void test_ECDH(void) BCRYPT_ECCKEY_BLOB *ecckey; BCRYPT_ALG_HANDLE alg; BCRYPT_KEY_HANDLE key, privkey, pubkey; + BCRYPT_SECRET_HANDLE secret; NTSTATUS status; ULONG size;
@@ -2008,6 +2028,40 @@ static void test_ECDH(void) ok(!memcmp(buf, eccprivkey, size), "wrong data\n"); HeapFree(GetProcessHeap(), 0, buf);
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubkey, ecdh_pubkey, sizeof(ecdh_pubkey), 0); + ok(status == STATUS_SUCCESS, "got %08x\n", status); + + status = pBCryptSecretAgreement(privkey, pubkey, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08x\n", status); + + if (status == STATUS_SUCCESS) + { + /* verify result on windows 10 */ + status = pBCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &size, 0); + + if (status == STATUS_NOT_SUPPORTED) + { + win_skip("BCRYPT_KDF_RAW_SECRET not supported\n"); + goto over; + } + + todo_wine ok(status == STATUS_SUCCESS, "got %08x\n", status); + + if (status == STATUS_SUCCESS) + { + ok (size, "size not set\n"); + buf = HeapAlloc(GetProcessHeap(), 0, size); + status = pBCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %08x\n", status); + ok(size == 32, "size of secret key incorrect, got %u, expected 32\n", size); + ok(!(memcmp(ecdh_secret, buf, size)), "wrong data\n"); + HeapFree(GetProcessHeap(), 0, buf); + } + } + + over: + pBCryptDestroySecret(secret); + pBCryptDestroyKey(pubkey); pBCryptDestroyKey(privkey); pBCryptCloseAlgorithmProvider(alg, 0); } @@ -2284,6 +2338,9 @@ START_TEST(bcrypt) pBCryptSetProperty = (void *)GetProcAddress(module, "BCryptSetProperty"); pBCryptSignHash = (void *)GetProcAddress(module, "BCryptSignHash"); pBCryptVerifySignature = (void *)GetProcAddress(module, "BCryptVerifySignature"); + pBCryptSecretAgreement = (void *)GetProcAddress(module, "BCryptSecretAgreement"); + pBCryptDestroySecret = (void *)GetProcAddress(module, "BCryptDestroySecret"); + pBCryptDeriveKey = (void *)GetProcAddress(module, "BCryptDeriveKey");
test_BCryptGenRandom(); test_BCryptGetFipsAlgorithmMode(); diff --git a/include/bcrypt.h b/include/bcrypt.h index 4546aea394..f393dc6e5c 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -92,6 +92,12 @@ typedef LONG NTSTATUS; #define BCRYPT_CHAIN_MODE_CFB L"ChainingModeCFB" #define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM" #define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM" + +#define BCRYPT_KDF_HASH L"HASH" +#define BCRYPT_KDF_HMAC L"HMAC" +#define BCRYPT_KDF_TLS_PRF L"TLS_PRF" +#define BCRYPT_KDF_SP80056A_CONCAT L"SP800_56A_CONCAT" +#define BCRYPT_KDF_RAW_SECRET L"TRUNCATE" #else static const WCHAR BCRYPT_ALGORITHM_NAME[] = {'A','l','g','o','r','i','t','h','m','N','a','m','e',0}; static const WCHAR BCRYPT_AUTH_TAG_LENGTH[] = {'A','u','t','h','T','a','g','L','e','n','g','t','h',0}; @@ -146,6 +152,12 @@ static const WCHAR BCRYPT_CHAIN_MODE_ECB[] = {'C','h','a','i','n','i','n','g','M static const WCHAR BCRYPT_CHAIN_MODE_CFB[] = {'C','h','a','i','n','i','n','g','M','o','d','e','C','F','B',0}; static const WCHAR BCRYPT_CHAIN_MODE_CCM[] = {'C','h','a','i','n','i','n','g','M','o','d','e','C','C','M',0}; static const WCHAR BCRYPT_CHAIN_MODE_GCM[] = {'C','h','a','i','n','i','n','g','M','o','d','e','G','C','M',0}; + +static const WCHAR BCRYPT_KDF_HASH[] = {'H','A','S','H',0}; +static const WCHAR BCRYPT_KDF_HMAC[] = {'H','M','A','C',0}; +static const WCHAR BCRYPT_KDF_TLS_PRF[] = {'T','L','S','_','P','R','F',0}; +static const WCHAR BCRYPT_KDF_SP80056A_CONCAT[] = {'S','P','8','0','0','_','5','6','A','_','C','O','N','C','A','T',0}; +static const WCHAR BCRYPT_KDF_RAW_SECRET[] = {'T','R','U','N','C','A','T','E',0}; #endif
#define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345