From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/rsaenh/tests/rsaenh.c | 137 +++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+)
diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index 6d784e2245d..a78f4fc0bf8 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -4,6 +4,7 @@ * Copyright (c) 2004 Michael Jung * Copyright (c) 2006 Juan Lang * Copyright (c) 2007 Vijay Kiran Kamuju + * Copyright (c) 2025 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -4200,8 +4201,144 @@ static void test_rc2_import(void) CryptDestroyKey(exchange_key); }
+static const BYTE PRIVATE_EXCH_blob[308] = { +0x07,0x02,0x00,0x00,0x00,0xa4,0x00,0x00,0x52,0x53,0x41,0x32,0x00,0x02,0x00,0x00, +0x01,0x00,0x01,0x00,0x55,0x7b,0x36,0x13,0xae,0x4b,0xc9,0x6f,0x78,0x1e,0xff,0x38, +0xd4,0x26,0x38,0x77,0x89,0x9b,0xf6,0x6b,0xf7,0xaa,0xea,0xad,0x27,0x11,0x1e,0xa5, +0x98,0x23,0xcb,0xaa,0x32,0x34,0xaf,0x19,0xd8,0x24,0x95,0xe4,0xae,0x4e,0x03,0x1d, +0x75,0xeb,0xec,0xc1,0x09,0xd0,0x02,0xed,0x1f,0x0e,0xcf,0x23,0xce,0xe9,0x09,0x34, +0xe3,0xc9,0xb9,0xbb,0xef,0x59,0x26,0xab,0xf5,0x11,0xdb,0x8d,0x0f,0x07,0xaf,0x53, +0x5c,0xaf,0xcd,0x8c,0xa2,0xaf,0x4e,0x3e,0xc9,0xe8,0x02,0x69,0x4b,0x87,0x1f,0xe1, +0x62,0x65,0x0a,0xf8,0xfb,0x92,0xce,0x69,0xcc,0xea,0x86,0x41,0x43,0xe8,0x4a,0x41, +0x75,0xf0,0xb6,0x17,0x64,0xa1,0x0e,0x52,0xd3,0x4c,0xdf,0x6f,0xa8,0x15,0x57,0x7c, +0x00,0xeb,0xbf,0xc1,0x69,0xfe,0x6d,0x50,0x55,0x89,0xfe,0x8a,0x1c,0x14,0x60,0xff, +0x5a,0xe6,0x80,0x22,0xa0,0xfc,0xe9,0x5f,0xa4,0x48,0xbb,0xc1,0xf0,0x4f,0xba,0x57, +0xeb,0x83,0xe9,0xe9,0x21,0x23,0x9a,0x83,0x71,0xd7,0x2e,0xb9,0x88,0x24,0x37,0x6b, +0x1d,0x73,0xcb,0x64,0xa4,0x6d,0xcf,0xed,0xbb,0x65,0x4c,0xf7,0xcc,0x86,0xf8,0x94, +0x40,0x61,0xb2,0x09,0x2e,0xea,0xb7,0xa2,0x1d,0xc2,0x4b,0x37,0x5d,0xc1,0x54,0xdf, +0x45,0x16,0x16,0xe1,0x08,0x6b,0xad,0x51,0xbf,0x62,0x0c,0xe0,0xe5,0x22,0x65,0xc5, +0x6a,0xca,0xc7,0xb0,0x49,0x48,0xae,0x6b,0x27,0x86,0xe8,0xe9,0x90,0x15,0x38,0x4f, +0x7f,0x3b,0x9e,0x38,0xd1,0x25,0x62,0x91,0xfe,0x18,0x08,0x79,0xcc,0x7c,0xaf,0x41, +0x8d,0xd1,0xa1,0xd3,0x63,0x3c,0xb0,0x7b,0x2d,0xda,0x6f,0x72,0x9c,0xd1,0xa8,0xaa, +0xb5,0x6a,0xde,0xed,0x00,0x0a,0x39,0xe9,0xc6,0x45,0x7a,0x39,0x6d,0x07,0x86,0xa9, +0xe5,0x4f,0xb4,0x9b }; +static const BYTE PUBLIC_EXCH_blob[84] = { +0x06,0x02,0x00,0x00,0x00,0xa4,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x02,0x00,0x00, +0x01,0x00,0x01,0x00,0x55,0x7b,0x36,0x13,0xae,0x4b,0xc9,0x6f,0x78,0x1e,0xff,0x38, +0xd4,0x26,0x38,0x77,0x89,0x9b,0xf6,0x6b,0xf7,0xaa,0xea,0xad,0x27,0x11,0x1e,0xa5, +0x98,0x23,0xcb,0xaa,0x32,0x34,0xaf,0x19,0xd8,0x24,0x95,0xe4,0xae,0x4e,0x03,0x1d, +0x75,0xeb,0xec,0xc1,0x09,0xd0,0x02,0xed,0x1f,0x0e,0xcf,0x23,0xce,0xe9,0x09,0x34, +0xe3,0xc9,0xb9,0xbb }; + +static void test_RC4_salt(void) +{ + static const BYTE zero[11]; + static const struct + { + const char *prov; + DWORD flags, key_length, salt_length; + } td[] = + { + { MS_DEF_PROV_A, 0, 0, 11 }, + { MS_DEF_PROV_A, 0, 40, 11 }, + { MS_DEF_PROV_A, CRYPT_NO_SALT, 40, 0 }, + { MS_DEF_PROV_A, 0, 56, 0 }, + { MS_DEF_PROV_A, CRYPT_CREATE_SALT, 56, 11 }, + { MS_ENHANCED_PROV_A, 0, 0, 0 }, + { MS_ENHANCED_PROV_A, 0, 40, 11 }, + { MS_ENHANCED_PROV_A, CRYPT_NO_SALT, 40, 0 }, + { MS_ENHANCED_PROV_A, CRYPT_CREATE_SALT, 40, 0 }, + { MS_ENHANCED_PROV_A, CRYPT_CREATE_SALT, 56, 0 }, + { MS_ENHANCED_PROV_A, CRYPT_CREATE_SALT, 128, 0 } + }; + HCRYPTPROV hprov; + HCRYPTKEY hkey, hkeyx; + DWORD i, key_length, size, blob_size; + void *blob; + BYTE salt[16], salt2[16]; + CRYPT_DATA_BLOB data; + BOOL ret; + + for (i = 0; i < ARRAY_SIZE(td); i++) + { + winetest_push_context("%lu", i); + + ret = CryptAcquireContextA(&hprov, NULL, td[i].prov, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + ok(ret, "error %#lx\n", GetLastError()); + + ret = CryptGenKey(hprov, CALG_RC4, (td[i].key_length << 16) | td[i].flags | CRYPT_EXPORTABLE, &hkey); + ok(ret, "error %#lx\n", GetLastError()); + + size = sizeof(key_length); + ret = CryptGetKeyParam(hkey, KP_KEYLEN, (BYTE *)&key_length, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + if (!strcmp(td[i].prov, MS_DEF_PROV_A)) + ok(key_length == (td[i].key_length ? td[i].key_length : 40), "got %lu, expected %lu\n", key_length, td[i].key_length); + else + ok(key_length == (td[i].key_length ? td[i].key_length : 128), "got %lu, expected %lu\n", key_length, td[i].key_length); + + size = 0xdeadbeef; + ret = CryptGetKeyParam(hkey, KP_SALT, NULL, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + todo_wine_if(i == 4 || i == 9) + ok(size == td[i].salt_length, "got %lu, expected %lu\n", size, td[i].salt_length); + if (size) + { + ret = CryptGetKeyParam(hkey, KP_SALT, salt, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + if (td[i].flags & CRYPT_CREATE_SALT) + ok(memcmp(salt, zero, size) != 0, "wrong salt %.11s\n", salt); + else todo_wine_if(i == 0 || i == 1 || i == 6) + ok(memcmp(salt, zero, size) == 0, "wrong salt %.11s\n", salt); + } + + memcpy(salt, (const BYTE *)"0123456789A", 11); + data.pbData = salt; + data.cbData = 11; + ret = CryptSetKeyParam(hkey, KP_SALT_EX, (BYTE *)&data, 0); + ok(ret, "error %#lx\n", GetLastError()); + + ret = CryptImportKey(hprov, PUBLIC_EXCH_blob, sizeof(PUBLIC_EXCH_blob), 0, 0, &hkeyx); + ok(ret, "error %#lx\n", GetLastError()); + + ret = CryptExportKey(hkey, hkeyx, SIMPLEBLOB, 0, NULL, &blob_size); + ok(ret, "error %#lx\n", GetLastError()); + blob = malloc(blob_size); + ret = CryptExportKey(hkey, hkeyx, SIMPLEBLOB, 0, blob, &blob_size); + ok(ret, "error %#lx\n", GetLastError()); + + CryptDestroyKey(hkey); + CryptDestroyKey(hkeyx); + + ret = CryptImportKey(hprov, PRIVATE_EXCH_blob, sizeof(PRIVATE_EXCH_blob), 0, 0, &hkeyx); + ok(ret, "error %#lx\n", GetLastError()); + + ret = CryptImportKey(hprov, blob, blob_size, hkeyx, 0, &hkey); + ok(ret, "error %#lx\n", GetLastError()); + size = 0xdeadbeef; + ret = CryptGetKeyParam(hkey, KP_SALT, NULL, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + if ((!strcmp(td[i].prov, MS_DEF_PROV_A) && !td[i].key_length) || td[i].key_length == 40) + ok(size == 11, "got %lu, expected 11\n", size); + else + ok(size == 0, "got %lu, expected 0\n", size); + ret = CryptGetKeyParam(hkey, KP_SALT, salt2, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + ok(!memcmp(salt2, zero, size), "wrong salt %.11s\n", salt2); + + free(blob); + CryptDestroyKey(hkey); + CryptDestroyKey(hkeyx); + CryptReleaseContext(hprov, 0); + + winetest_pop_context(); + } +} + START_TEST(rsaenh) { + test_RC4_salt(); + for (iProv = 0; iProv < ARRAY_SIZE(szProviders); iProv++) { if (!init_base_environment(szProviders[iProv], 0))
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/rsaenh/tests/rsaenh.c | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index a78f4fc0bf8..36ddc8ffdb6 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -4335,9 +4335,85 @@ static void test_RC4_salt(void) } }
+static void test_RC4_session_key(void) +{ + static const BYTE zero[11]; + static const char hello_world[12] = "Hello World!"; + BYTE data[sizeof(hello_world)], salt[11], salt2[11]; + HCRYPTPROV hprov; + HCRYPTKEY hkey, hkeyx; + DWORD size, blob_size; + void *blob; + BOOL ret; + + ret = CryptAcquireContextA(&hprov, NULL, MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + ok(ret, "error %#lx\n", GetLastError()); + + /* Client: Generate session key */ + ret = CryptGenKey(hprov, CALG_RC4, CRYPT_EXPORTABLE, &hkey); + ok(ret, "error %#lx\n", GetLastError()); + size = 0xdeadbeef; + ret = CryptGetKeyParam(hkey, KP_SALT, NULL, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + ok(size == 11, "got %lu\n", size); + ret = CryptGetKeyParam(hkey, KP_SALT, salt, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + todo_wine + ok(!memcmp(salt, zero, size), "wrong salt %.11s\n", salt); + + /* Client: Import the server's public key */ + ret = CryptImportKey(hprov, PUBLIC_EXCH_blob, sizeof(PUBLIC_EXCH_blob), 0, 0, &hkeyx); + ok(ret, "error %#lx\n", GetLastError()); + + /* Client: Export encrypted session key using the server's public key */ + ret = CryptExportKey(hkey, hkeyx, SIMPLEBLOB, 0, NULL, &blob_size); + ok(ret, "error %#lx\n", GetLastError()); + blob = malloc(blob_size); + ret = CryptExportKey(hkey, hkeyx, SIMPLEBLOB, 0, blob, &blob_size); + ok(ret, "error %#lx\n", GetLastError()); + + /* Client: Encrypt data using the session key */ + size = sizeof(hello_world); + memcpy(data, hello_world, size); + ret = CryptEncrypt(hkey, 0, TRUE, 0, data, &size, size); + ok(ret, "error %#lx\n", GetLastError()); + + CryptDestroyKey(hkeyx); + CryptDestroyKey(hkey); + + /* Server: Use the server's private key */ + ret = CryptImportKey(hprov, PRIVATE_EXCH_blob, sizeof(PRIVATE_EXCH_blob), 0, 0, &hkeyx); + ok(ret, "error %#lx\n", GetLastError()); + + /* Server: Import encrypted session key using the server's private key */ + ret = CryptImportKey(hprov, blob, blob_size, hkeyx, 0, &hkey); + ok(ret, "error %#lx\n", GetLastError()); + size = 0xdeadbeef; + ret = CryptGetKeyParam(hkey, KP_SALT, NULL, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + ok(size == 11, "got %lu\n", size); + ret = CryptGetKeyParam(hkey, KP_SALT, salt2, &size, 0); + ok(ret, "error %#lx\n", GetLastError()); + ok(!memcmp(salt2, zero, size), "wrong salt %.11s\n", salt2); + + /* Server: Decrypt data using the session key */ + size = sizeof(hello_world); + ret = CryptDecrypt(hkey, 0, TRUE, 0, data, &size); + ok(ret, "error %#lx\n", GetLastError()); + ok(size == sizeof(hello_world), "got %lu\n", size); + todo_wine + ok(!memcmp(data, hello_world, size), "wrong data\n"); + + free(blob); + CryptDestroyKey(hkey); + CryptDestroyKey(hkeyx); + CryptReleaseContext(hprov, 0); +} + START_TEST(rsaenh) { test_RC4_salt(); + test_RC4_session_key();
for (iProv = 0; iProv < ARRAY_SIZE(szProviders); iProv++) {