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).

This commit is contained in:
Thomas Pornin 2017-06-22 21:13:15 +02:00
parent 7f343eedfc
commit eaa0d38fa8
2 changed files with 68 additions and 1 deletions

View file

@ -78,14 +78,16 @@ br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx,
if (len >= 48) { if (len >= 48) {
x2 = _mm_loadu_si128( x2 = _mm_loadu_si128(
(void *)(buf + 32)); (void *)(buf + 32));
x3 = x2;
} else { } else {
x2 = x0; x2 = x0;
x3 = x1;
} }
} else { } else {
x1 = x0; x1 = x0;
x2 = x0; x2 = x0;
x3 = x0;
} }
x3 = x0;
} }
e0 = x0; e0 = x0;
e1 = x1; e1 = x1;

View file

@ -3133,6 +3133,71 @@ test_AES_generic(char *name,
check_equals("KAT CBC AES decrypt (2)", check_equals("KAT CBC AES decrypt (2)",
buf, plain, data_len); 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) { if (vc != NULL) {