FreeRDP
Loading...
Searching...
No Matches
TestCryptoCipherIV.c
1/*
2 * WinPR regression test: winpr_Cipher_NewEx() must honor the caller-provided IV
3 * (backend-independent).
4 *
5 * Motivated by: on mbedTLS builds the mbedTLS branch of winpr_Cipher_NewEx()
6 * never calls mbedtls_cipher_set_iv(), so the IV argument is silently ignored
7 * (see winpr/libwinpr/crypto/cipher.c, OpenSSL branch :619 vs mbedTLS branch
8 * :625-649). The existing TestCryptoCipher round-trip cannot detect this,
9 * because it uses the same (ignored) IV for encryption and decryption.
10 *
11 * This test has two independent checks (AES-128-CBC):
12 * 1) NIST SP 800-38A F.2.1, CBC-AES128, block #1 known-answer test
13 * 2) The API contract: same key + same plaintext + different IV must yield
14 * different ciphertexts
15 *
16 * Expected result: pass on all backends that honor the IV (OpenSSL, and
17 * mbedTLS after the fix). The test fails on an unpatched mbedTLS build.
18 *
19 * To wire up: add TestCryptoCipherIV.c to TESTS in
20 * winpr/libwinpr/crypto/test/CMakeLists.txt and run
21 * TestCrypto TestCryptoCipherIV
22 */
23#include <winpr/crt.h>
24#include <winpr/crypto.h>
25#include <winpr/print.h>
26#include <winpr/ssl.h>
27
28#include <stdio.h>
29#include <string.h>
30
31static BOOL encrypt_aes128cbc(const BYTE* key, size_t keylen, const BYTE* iv, size_t ivlen,
32 const BYTE* in, size_t inlen, BYTE* out, size_t* outlen)
33{
34 WINPR_CIPHER_CTX* ctx =
35 winpr_Cipher_NewEx(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, keylen, iv, ivlen);
36 size_t o = 0;
37 size_t f = 0;
38
39 if (!ctx)
40 return FALSE;
41
42 if (!winpr_Cipher_Update(ctx, in, inlen, out, &o))
43 goto fail;
44
45 if (!winpr_Cipher_Final(ctx, out + o, &f))
46 goto fail;
47
48 *outlen = o + f;
49 winpr_Cipher_Free(ctx);
50 return TRUE;
51
52fail:
53 winpr_Cipher_Free(ctx);
54 return FALSE;
55}
56
57int TestCryptoCipherIV(int argc, char* argv[])
58{
59 /* NIST SP 800-38A F.2.1: CBC-AES128.Encrypt, block #1 */
60 const BYTE kat_key[16] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
61 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
62 const BYTE kat_iv[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
63 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
64 const BYTE kat_pt[16] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
65 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a };
66 const BYTE kat_ct[16] = { 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
67 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d };
68
69 BYTE iv1[16];
70 BYTE iv2[16];
71 BYTE c_kat[32];
72 BYTE c1[32];
73 BYTE c2[32];
74 size_t l_kat = 0;
75 size_t l1 = 0;
76 size_t l2 = 0;
77 int rc = -1;
78
79 WINPR_UNUSED(argc);
80 WINPR_UNUSED(argv);
81
82 if (!winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
83 {
84 (void)fprintf(stderr, "%s: winpr_InitializeSSL failed\n", __func__);
85 return -1;
86 }
87
88 memset(iv1, 0x11, sizeof(iv1));
89 memset(iv2, 0x22, sizeof(iv2));
90
91 if (!encrypt_aes128cbc(kat_key, sizeof(kat_key), kat_iv, sizeof(kat_iv), kat_pt, sizeof(kat_pt),
92 c_kat, &l_kat) ||
93 !encrypt_aes128cbc(kat_key, sizeof(kat_key), iv1, sizeof(iv1), kat_pt, sizeof(kat_pt), c1,
94 &l1) ||
95 !encrypt_aes128cbc(kat_key, sizeof(kat_key), iv2, sizeof(iv2), kat_pt, sizeof(kat_pt), c2,
96 &l2))
97 {
98 (void)fprintf(stderr, "%s: encryption failed\n", __func__);
99 return -1;
100 }
101
102 if ((l_kat != sizeof(kat_ct)) || (memcmp(c_kat, kat_ct, sizeof(kat_ct)) != 0))
103 {
104 (void)fprintf(stderr,
105 "%s: AES-128-CBC known-answer test failed - the IV is not honored by the "
106 "cipher backend\n",
107 __func__);
108 goto out;
109 }
110
111 if ((l1 != l2) || (memcmp(c1, c2, l1) == 0))
112 {
113 (void)fprintf(stderr,
114 "%s: ciphertexts with different IVs are identical - the IV is not honored "
115 "by the cipher backend\n",
116 __func__);
117 goto out;
118 }
119
120 (void)printf("%s: IV handling OK\n", __func__);
121 rc = 0;
122
123out:
124 return rc;
125}