mirror of https://github.com/wolfSSL/wolfBoot.git
F-7966: propagate the CTR counter carry without branching on the nonce
aes_set_iv() and pkcs11_crypto_set_iv() added the block counter to the nonce-derived counter block and propagated the carry with a loop that only runs - and whose trip count depends - on the nonce words: the overflow branch reveals that the high word was within one count of wrapping, and the inner loop's exit point reveals how many of the low words are 0xFFFFFFFF. crypto_set_iv() runs once per encrypted block, so a timing attacker gets one measurement per block. Replace both with an unconditional branch-free four-word carry (standard carry-out flags, three iterations regardless of content). Arithmetic is identical: verified old-vs-new expression equality over 5M random counter/nonce inputs plus the full-carry, zero-counter and max-counter boundary cases; unit-aes128/unit-aes256 encrypted roundtrips pass with the new code, and the ENCRYPT_PKCS11 CKM_AES_CTR path compiles clean.pull/868/head
parent
f3098cbf6d
commit
495b80b9b0
|
|
@ -2314,12 +2314,18 @@ void aes_set_iv(uint8_t *nonce, uint32_t iv_ctr)
|
|||
iv_buf[i] = wb_reverse_word32(iv_buf[i]);
|
||||
}
|
||||
#endif
|
||||
iv_buf[3] += iv_ctr;
|
||||
if (iv_buf[3] < iv_ctr) { /* overflow */
|
||||
/* Add the block counter with an unconditional, branch-free carry:
|
||||
* a conditional carry loop's trip count would depend on the nonce
|
||||
* content and leak it through timing. */
|
||||
{
|
||||
uint32_t carry;
|
||||
uint32_t old = iv_buf[3];
|
||||
iv_buf[3] = old + iv_ctr;
|
||||
carry = (uint32_t)(iv_buf[3] < old);
|
||||
for (i = 2; i >= 0; i--) {
|
||||
iv_buf[i]++;
|
||||
if (iv_buf[i] != 0)
|
||||
break;
|
||||
uint32_t prev = iv_buf[i];
|
||||
iv_buf[i] = prev + carry;
|
||||
carry = (uint32_t)(iv_buf[i] < prev);
|
||||
}
|
||||
}
|
||||
#ifndef BIG_ENDIAN_ORDER
|
||||
|
|
@ -2474,12 +2480,16 @@ void pkcs11_crypto_set_iv(uint8_t *nonce, uint32_t iv_ctr)
|
|||
cb_words[i] = wb_reverse_word32(cb_words[i]);
|
||||
}
|
||||
#endif
|
||||
cb_words[3] += iv_ctr;
|
||||
if (cb_words[3] < iv_ctr) { /* overflow */
|
||||
/* Unconditional, branch-free carry (see aes_set_iv) */
|
||||
{
|
||||
uint32_t carry;
|
||||
uint32_t old = cb_words[3];
|
||||
cb_words[3] = old + iv_ctr;
|
||||
carry = (uint32_t)(cb_words[3] < old);
|
||||
for (i = 2; i >= 0; i--) {
|
||||
cb_words[i]++;
|
||||
if (cb_words[i] != 0)
|
||||
break;
|
||||
uint32_t prev = cb_words[i];
|
||||
cb_words[i] = prev + carry;
|
||||
carry = (uint32_t)(cb_words[i] < prev);
|
||||
}
|
||||
}
|
||||
#ifndef BIG_ENDIAN_ORDER
|
||||
|
|
|
|||
Loading…
Reference in New Issue