Fixes Age of Empires III not being able to find its servers / multiplayer games. That regressed with the following commit: ``` commit 745df5915cf4c7411d69b4fd2ba5d05a333f3947 Author: Hans Leidekker hans@codeweavers.com Date: Wed Aug 31 09:42:11 2022 +0200
bcrypt: Force symmetric key reset if necessary.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52457 ```
The core problem is not in this commit though. The bit of the commit which regressed AoE is removing ```!is_zero_vector( vector, vector_len )``` condition in key_symmetric_set_vector() which was previously also forcing key reset (which was resetting key to the set value whenever the key is nonempty). That was apparently breaking other things, that's why it was probably removed.
The actual culprit is that BCryptEncrypt() / BCryptEncrypt() modify init vector on output in AES CBC and CFB mode on Windows. So, to properly sync our gnutls key we need to return the value in IV parameter like Windows does and decide whether the key needs update or not based on comparison with the actual dynamic key state, not with the value set initially. The game sets the IV data over multiple encrypt or decrypt call (sets it with its own fixed value overwriting what Windows returns in those). Before the blamed commit that worked because key_symmetric_set_vector() was always pushing the given key to gnutls. But that was breaking apps which worked differently (which way is probably a more expected usage) which set IV with their only once initially and then either: - pass the same buffer, which on Windows has the updated IV and in Wine was always the same, thus the changed in blamed commit fixed the thing by keeping the internal state of gnutls key untouched; - pass NULL buffer; this case I suppose didn't work correctly neither before nor after the blamed commit but should be also fixed by this MR.
Besides newly added tests (which cover IV output data plus some additional cases of encryption with auto-modified state) the MR is fixing a few rather unfortunate existing todo's.
Now, the implementation. My first instinct was to try to extract that updated state from gnutls, but: 1. It seems like there is no exported function which would give this updated state. There is _gnutls_cipher_get_iv() used in tests but it doesn't even seem to work for AES / CBC; 2. The comment above _gnutls_cipher_get_iv() says: ``` * This is solely for validation purposes of our crypto * implementation. For other purposes, the IV can be typically * calculated from the initial IV value and the subsequent ciphertext * values. ``` So it doesn't look like gnutls is planning to export anything like that. Also, it is not apparent that "init vector" is generally equivalent to the dynamic cipher hash, and the fact that Windows returns that in the IV vector back look rather implementation specific. So, also given that the updated state hash value is the simply taken from the last encrypted data block (input on decrypt and output on encrypt) I hope it is ok to just code that.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/bcrypt/tests/bcrypt.c | 108 +++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 5d1a80f330b..65a812d59d1 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -739,6 +739,10 @@ static void test_BCryptGenerateSymmetricKey(void) {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; static UCHAR expected[] = {0xc6,0xa1,0x3b,0x37,0x87,0x8f,0x5b,0x82,0x6f,0x4f,0x81,0x62,0xa1,0xc8,0xd8,0x79}; + static UCHAR expected2[] = + {0xb5,0x8a,0x10,0x64,0xd8,0xac,0xa9,0x9b,0xd9,0xb0,0x40,0x5b,0x85,0x45,0xf5,0xbb}; + static UCHAR expected3[] = + {0xe3,0x7c,0xd3,0x63,0xdd,0x7c,0x87,0xa0,0x9a,0xff,0x0e,0x3e,0x60,0xe0,0x9c,0x82}; BCRYPT_ALG_HANDLE aes; BCRYPT_KEY_HANDLE key, key2; UCHAR *buf, ciphertext[16], plaintext[16], ivbuf[16], mode[64]; @@ -821,6 +825,7 @@ static void test_BCryptGenerateSymmetricKey(void) ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -831,6 +836,26 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + + size = 0; + memset(ciphertext, 0, sizeof(ciphertext)); + ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 16, "got %lu\n", size); + todo_wine ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); + + size = 0; + memcpy(ivbuf, iv, sizeof(iv)); + ++ivbuf[0]; + memset(ciphertext, 0, sizeof(ciphertext)); + ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, ciphertext, 16, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 16, "got %lu\n", size); + ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); + for (i = 0; i < 16; i++) + ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
key2 = (void *)0xdeadbeef; ret = BCryptDuplicateKey(NULL, &key2, NULL, 0, 0); @@ -858,6 +883,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
ret = BCryptDestroyKey(key2); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -881,6 +907,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); ok(!memcmp(plaintext, data, sizeof(data)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
memset(mode, 0, sizeof(mode)); ret = BCryptGetProperty(key, BCRYPT_CHAINING_MODE, mode, sizeof(mode), &size, 0); @@ -1083,6 +1110,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1093,6 +1121,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* NULL initialization vector */ size = 0; @@ -1112,6 +1141,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected9, sizeof(expected9)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected9[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected9[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* input size is not a multiple of block size */ size = 0; @@ -1126,6 +1156,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 17, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1136,6 +1167,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected2[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected2[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n");
/* input size is a multiple of block size, block padding set */ size = 0; @@ -1143,6 +1175,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1153,6 +1186,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
/* output size too small */ size = 0; @@ -1191,6 +1225,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1201,6 +1236,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected10, sizeof(expected10)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected10[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected10[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1267,6 +1303,7 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag[i]); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
/* NULL initialization vector */ size = 0; @@ -1296,6 +1333,8 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag[i]); + memset(ciphertext, 0, sizeof(iv)); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* input size is not multiple of block size */ size = 0; @@ -1311,6 +1350,7 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag2[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag2[i]); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
/* test with auth data */ auth_info.pbAuthData = auth_data; @@ -1329,6 +1369,7 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag3[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag3[i]); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
memset(tag, 0xff, sizeof(tag)); ret = BCryptEncrypt(key, data2, 0, &auth_info, ivbuf, 16, NULL, 0, &size, 0); @@ -1496,6 +1537,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1506,6 +1548,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected11, sizeof(expected11)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected11[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected11[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* NULL initialization vector */ size = 0; @@ -1525,6 +1568,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected13, sizeof(expected13)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected13[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected13[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* input size is not a multiple of block size */ size = 0; @@ -1539,6 +1583,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 17, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1549,6 +1594,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected14, sizeof(expected14)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected14[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected14[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n");
/* input size is a multiple of block size, block padding set */ size = 0; @@ -1566,6 +1612,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected15, sizeof(expected15)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected15[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected15[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
/* output size too small */ size = 0; @@ -1574,6 +1621,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 17, NULL, ivbuf, 16, ciphertext, 31, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1581,6 +1629,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, ciphertext, 32, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1604,6 +1653,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1614,6 +1664,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected16, sizeof(expected16)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected16[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected16[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
ret = BCryptCloseAlgorithmProvider(aes, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1636,6 +1687,12 @@ static void test_BCryptDecrypt(void) static UCHAR expected3[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10}; + static UCHAR expected4[] = + {0x28,0x73,0x3d,0xef,0x84,0x8f,0xb0,0xa6,0x5d,0x1a,0x51,0xb7,0xec,0x8f,0xea,0xe9, + 0x10,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f}; + static UCHAR expected5[] = + {0x29,0x73,0x3d,0xef,0x84,0x8f,0xb0,0xa6,0x5d,0x1a,0x51,0xb7,0xec,0x8f,0xea,0xe9, + 0x10,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f}; static UCHAR ciphertext[32] = {0xc6,0xa1,0x3b,0x37,0x87,0x8f,0x5b,0x82,0x6f,0x4f,0x81,0x62,0xa1,0xc8,0xd8,0x79, 0x28,0x73,0x3d,0xef,0x84,0x8f,0xb0,0xa6,0x5d,0x1a,0x51,0xb7,0xec,0x8f,0xea,0xe9}; @@ -1702,6 +1759,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext, 32, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1710,6 +1768,23 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected, sizeof(expected)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext + size - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + + size = 0; + ++ivbuf[0]; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext, 32, NULL, ivbuf, 16, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + todo_wine ok(!memcmp(plaintext, expected5, sizeof(expected)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + + size = 0; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext, 32, NULL, NULL, 0, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + todo_wine ok(!memcmp(plaintext, expected4, sizeof(expected4)), "wrong data\n");
/* test with padding smaller than block size */ size = 0; @@ -1717,6 +1792,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext2, 32, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1725,6 +1801,15 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 17, "got %lu\n", size); ok(!memcmp(plaintext, expected2, sizeof(expected2)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + + size = 0; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext2, 32, NULL, ivbuf, 16, plaintext, 17, &size, BCRYPT_BLOCK_PADDING); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 17, "got %lu\n", size); + todo_wine ok(!memcmp(plaintext, expected4, size), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - 16, sizeof(iv)), "wrong iv data.\n");
/* test with padding of block size */ size = 0; @@ -1732,6 +1817,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext3, 48, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1740,6 +1826,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext3 + 48 - 16, sizeof(iv)), "wrong iv data.\n");
/* output size too small */ size = 0; @@ -1816,6 +1903,25 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv.\n"); + + size = 0; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, NULL, 0, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + + size = 0; + memcpy(ivbuf, iv, sizeof(iv)); + ++ivbuf[0]; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + ok(!memcmp(ivbuf + 1, iv + 1, sizeof(iv) - 1), "wrong iv data.\n"); + ok(ivbuf[0] == iv[0] + 1, "wrong iv data.\n");
/* test with auth data */ auth_info.pbAuthData = auth_data; @@ -1830,6 +1936,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv.\n");
/* test with wrong tag */ memcpy(ivbuf, iv, sizeof(iv)); @@ -1837,6 +1944,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, plaintext, 32, &size, 0); ok(ret == STATUS_AUTH_TAG_MISMATCH, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 20 +++++++++++++++++ dlls/bcrypt/tests/bcrypt.c | 44 +++++++++++++++++++------------------- 2 files changed, 42 insertions(+), 22 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index cf05e8b4d44..c5fc6391f38 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1418,6 +1418,16 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp free( buf ); }
+ if (!status) + { + if (key->u.s.vector && *ret_len >= key->u.s.vector_len) + { + memcpy( key->u.s.vector, output + *ret_len - key->u.s.vector_len, key->u.s.vector_len ); + if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + } + else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + } + return status; }
@@ -1515,6 +1525,16 @@ static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG inpu free( buf ); }
+ if (!status) + { + if (key->u.s.vector && input_len >= key->u.s.vector_len) + { + memcpy( key->u.s.vector, input + input_len - key->u.s.vector_len, key->u.s.vector_len ); + if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + } + else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + } + return status; }
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 65a812d59d1..9f8d0145735 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -836,7 +836,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
size = 0; memset(ciphertext, 0, sizeof(ciphertext)); @@ -855,7 +855,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
key2 = (void *)0xdeadbeef; ret = BCryptDuplicateKey(NULL, &key2, NULL, 0, 0); @@ -883,7 +883,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
ret = BCryptDestroyKey(key2); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -907,7 +907,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); ok(!memcmp(plaintext, data, sizeof(data)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
memset(mode, 0, sizeof(mode)); ret = BCryptGetProperty(key, BCRYPT_CHAINING_MODE, mode, sizeof(mode), &size, 0); @@ -1121,7 +1121,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* NULL initialization vector */ size = 0; @@ -1141,7 +1141,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected9, sizeof(expected9)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected9[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected9[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* input size is not a multiple of block size */ size = 0; @@ -1167,7 +1167,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected2[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected2[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n");
/* input size is a multiple of block size, block padding set */ size = 0; @@ -1186,7 +1186,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
/* output size too small */ size = 0; @@ -1236,7 +1236,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected10, sizeof(expected10)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected10[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected10[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1548,7 +1548,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected11, sizeof(expected11)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected11[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected11[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* NULL initialization vector */ size = 0; @@ -1568,7 +1568,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected13, sizeof(expected13)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected13[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected13[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n");
/* input size is not a multiple of block size */ size = 0; @@ -1594,7 +1594,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected14, sizeof(expected14)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected14[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected14[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n");
/* input size is a multiple of block size, block padding set */ size = 0; @@ -1612,7 +1612,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected15, sizeof(expected15)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected15[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected15[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
/* output size too small */ size = 0; @@ -1664,7 +1664,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected16, sizeof(expected16)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected16[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected16[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n");
ret = BCryptCloseAlgorithmProvider(aes, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1768,7 +1768,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected, sizeof(expected)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext + size - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + size - sizeof(iv), sizeof(iv)), "wrong iv data.\n");
size = 0; ++ivbuf[0]; @@ -1776,8 +1776,8 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext, 32, NULL, ivbuf, 16, plaintext, 32, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); - todo_wine ok(!memcmp(plaintext, expected5, sizeof(expected)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(plaintext, expected5, sizeof(expected)), "wrong data\n"); + ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n");
size = 0; memset(plaintext, 0, sizeof(plaintext)); @@ -1801,15 +1801,15 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 17, "got %lu\n", size); ok(!memcmp(plaintext, expected2, sizeof(expected2)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext2 + 32 - sizeof(iv), sizeof(iv)), "wrong iv data.\n");
size = 0; memset(plaintext, 0, sizeof(plaintext)); ret = BCryptDecrypt(key, ciphertext2, 32, NULL, ivbuf, 16, plaintext, 17, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 17, "got %lu\n", size); - todo_wine ok(!memcmp(plaintext, expected4, size), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(plaintext, expected4, size), "wrong data\n"); + ok(!memcmp(ivbuf, ciphertext2 + 32 - 16, sizeof(iv)), "wrong iv data.\n");
/* test with padding of block size */ size = 0; @@ -1826,7 +1826,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext3 + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext3 + 48 - 16, sizeof(iv)), "wrong iv data.\n");
/* output size too small */ size = 0; @@ -3256,7 +3256,7 @@ static void test_aes_vector(void) ret = BCryptEncrypt(key, input, sizeof(input), NULL, iv, sizeof(iv), output, sizeof(output), &size, 0); ok(!ret, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(output, expect3, sizeof(expect3)), "wrong cipher text\n"); + ok(!memcmp(output, expect3, sizeof(expect3)), "wrong cipher text\n");
ret = BCryptDestroyKey(key); ok(!ret, "got %#lx\n", ret);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 8 ++++---- dlls/bcrypt/tests/bcrypt.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index c5fc6391f38..ca5b934a8d5 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1149,12 +1149,12 @@ static BOOL is_equal_vector( const UCHAR *vector, ULONG len, const UCHAR *vector static NTSTATUS key_symmetric_set_vector( struct key *key, UCHAR *vector, ULONG vector_len, BOOL force_reset ) { BOOL needs_reset = force_reset || !is_equal_vector( key->u.s.vector, key->u.s.vector_len, vector, vector_len ); - - free( key->u.s.vector ); - key->u.s.vector = NULL; - key->u.s.vector_len = 0; if (vector) { + free( key->u.s.vector ); + key->u.s.vector = NULL; + key->u.s.vector_len = 0; + if (!(key->u.s.vector = malloc( vector_len ))) return STATUS_NO_MEMORY; memcpy( key->u.s.vector, vector, vector_len ); key->u.s.vector_len = vector_len; diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 9f8d0145735..19518480ee0 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -843,7 +843,7 @@ static void test_BCryptGenerateSymmetricKey(void) ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); + ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n");
size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1129,7 +1129,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(ciphertext, expected8, sizeof(expected8)), "wrong data\n"); + ok(!memcmp(ciphertext, expected8, sizeof(expected8)), "wrong data\n");
/* all zero initialization vector */ size = 0; @@ -1556,7 +1556,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(ciphertext, expected12, sizeof(expected12)), "wrong data\n"); + ok(!memcmp(ciphertext, expected12, sizeof(expected12)), "wrong data\n");
/* all zero initialization vector */ size = 0; @@ -1784,7 +1784,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext, 32, NULL, NULL, 0, plaintext, 32, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); - todo_wine ok(!memcmp(plaintext, expected4, sizeof(expected4)), "wrong data\n"); + ok(!memcmp(plaintext, expected4, sizeof(expected4)), "wrong data\n");
/* test with padding smaller than block size */ size = 0;
This merge request was approved by Hans Leidekker.