From 3347bd81b75e4e2e5c39de70d8771db37b380daa Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 9 Jan 2019 21:58:08 +0000 Subject: [PATCH] Fix AES-NI SDCTR to pass the new tests. The IV-incrementing code seems to have had several bugs. It was not propagating a carry from bit 31 to 32 of the 128-bit integer, apparently because of having arranged the 32-bit words wrongly within the vector register; also, when it tried to implement carry propagation from bit 63 to 64 by checking the low 64 bits for zero, it checked the _high_ bits instead, leading to a spurious extra addition in the low half if the high half happened to be zero. This must surely have been able to cause mysterious decryption failures about once every 2^32 cipher blocks = 64Gb of data transferred. I suppose that must be a large enough number that either no users of the snapshot builds have encountered the problem, or the ones who did dismissed it as computers being randomly flaky. The revised version now passes all the same tests as the software implementation. --- sshaes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sshaes.c b/sshaes.c index 40f3341e..4e2ada56 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1572,8 +1572,8 @@ static void aes_decrypt_cbc_ni(unsigned char *blk, int len, AESContext * ctx) FUNC_ISA static void aes_sdctr_ni(unsigned char *blk, int len, AESContext *ctx) { - const __m128i BSWAP_EPI64 = _mm_setr_epi8(3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12); - const __m128i ONE = _mm_setr_epi32(0,0,0,1); + const __m128i BSWAP_EPI64 = _mm_setr_epi8(7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8); + const __m128i ONE = _mm_setr_epi32(0,0,1,0); const __m128i ZERO = _mm_setzero_si128(); __m128i iv; __m128i* block = (__m128i*)blk; @@ -1620,7 +1620,7 @@ static void aes_sdctr_ni(unsigned char *blk, int len, AESContext *ctx) iv = _mm_shuffle_epi8(iv, BSWAP_EPI64); /* Swap endianess */ iv = _mm_add_epi64(iv, ONE); /* Inc low part */ enc = _mm_cmpeq_epi64(iv, ZERO); /* Check for carry */ - enc = _mm_unpacklo_epi64(ZERO, enc); /* Pack carry reg */ + enc = _mm_unpackhi_epi64(enc, ZERO); /* Pack carry reg */ iv = _mm_sub_epi64(iv, enc); /* Sub carry reg */ iv = _mm_shuffle_epi8(iv, BSWAP_EPI64); /* Swap enianess back */