From: Thomas Pornin Date: Thu, 22 Jun 2017 19:13:15 +0000 (+0200) Subject: Fixed IV processing for CBC decryption with AES (x86ni implementation) when data... X-Git-Tag: v0.5~13 X-Git-Url: https://bearssl.org/gitweb//home/git/?p=BearSSL;a=commitdiff_plain;h=eaa0d38fa8d514aab87b56c6a27d75fa06cdec7e Fixed IV processing for CBC decryption with AES (x86ni implementation) when data length is not multiple of 64 bytes (the bug was breaking TLS 1.0 AES/CBC on recent x86 systems). --- diff --git a/src/symcipher/aes_x86ni_cbcdec.c b/src/symcipher/aes_x86ni_cbcdec.c index e140b9f..c97ce48 100644 --- a/src/symcipher/aes_x86ni_cbcdec.c +++ b/src/symcipher/aes_x86ni_cbcdec.c @@ -78,14 +78,16 @@ br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, if (len >= 48) { x2 = _mm_loadu_si128( (void *)(buf + 32)); + x3 = x2; } else { x2 = x0; + x3 = x1; } } else { x1 = x0; x2 = x0; + x3 = x0; } - x3 = x0; } e0 = x0; e1 = x1; diff --git a/test/test_crypto.c b/test/test_crypto.c index 47c6bf6..fd0b396 100644 --- a/test/test_crypto.c +++ b/test/test_crypto.c @@ -3133,6 +3133,71 @@ test_AES_generic(char *name, check_equals("KAT CBC AES decrypt (2)", buf, plain, data_len); } + + /* + * We want to check proper IV management for CBC: + * encryption and decryption must properly copy the _last_ + * encrypted block as new IV, for all sizes. + */ + for (u = 1; u <= 35; u ++) { + br_hmac_drbg_context rng; + unsigned char x; + size_t key_len, data_len; + size_t v; + + br_hmac_drbg_init(&rng, &br_sha256_vtable, + "seed for AES/CBC", 16); + x = u; + br_hmac_drbg_update(&rng, &x, 1); + data_len = u << 4; + for (key_len = 16; key_len <= 32; key_len += 16) { + unsigned char key[32]; + unsigned char iv[16], iv1[16], iv2[16]; + unsigned char plain[35 * 16]; + unsigned char tmp1[sizeof plain]; + unsigned char tmp2[sizeof plain]; + br_aes_gen_cbcenc_keys v_ec; + br_aes_gen_cbcdec_keys v_dc; + const br_block_cbcenc_class **ec; + const br_block_cbcdec_class **dc; + + br_hmac_drbg_generate(&rng, key, key_len); + br_hmac_drbg_generate(&rng, iv, sizeof iv); + br_hmac_drbg_generate(&rng, plain, data_len); + + ec = &v_ec.vtable; + ve->init(ec, key, key_len); + memcpy(iv1, iv, sizeof iv); + memcpy(tmp1, plain, data_len); + ve->run(ec, iv1, tmp1, data_len); + check_equals("IV CBC AES (1)", + tmp1 + data_len - 16, iv1, 16); + memcpy(iv2, iv, sizeof iv); + memcpy(tmp2, plain, data_len); + for (v = 0; v < data_len; v += 16) { + ve->run(ec, iv2, tmp2 + v, 16); + } + check_equals("IV CBC AES (2)", + tmp2 + data_len - 16, iv2, 16); + check_equals("IV CBC AES (3)", + tmp1, tmp2, data_len); + + dc = &v_dc.vtable; + vd->init(dc, key, key_len); + memcpy(iv1, iv, sizeof iv); + vd->run(dc, iv1, tmp1, data_len); + check_equals("IV CBC AES (4)", iv1, iv2, 16); + check_equals("IV CBC AES (5)", + tmp1, plain, data_len); + memcpy(iv2, iv, sizeof iv); + for (v = 0; v < data_len; v += 16) { + vd->run(dc, iv2, tmp2 + v, 16); + } + check_equals("IV CBC AES (6)", iv1, iv2, 16); + check_equals("IV CBC AES (7)", + tmp2, plain, data_len); + } + } } if (vc != NULL) {