Skip to content

Commit

Permalink
aes_gcm: Add counter test for max input/output length.
Browse files Browse the repository at this point in the history
For *ring* 0.17.12, both of these tests pass for default release mode,
release mode with overflow-checks=true, and debug mode, on 64-bit and
32-bit targets.

For prior releases, `test_aes_gcm_counter_blocks_max_minus_one` passes
in all three modes.

For prior releases, `test_aes_gcm_counter_blocks_max` passes in default
release mode:
```
$ cargo test --lib test_aes_gcm_counter_blocks --release
[snip]
test aead::aes::aes_gcm_tests::test_aes_gcm_counter_blocks_max ... ok
test aead::aes::aes_gcm_tests::test_aes_gcm_counter_blocks_max_minus_one ... ok
```
But, for 64-bit targets, when overflow checks are enabled (including debug mode),
`test_aes_gcm_counter_blocks_max` fails:

```
$ RUSTFLAGS="-C overflow-checks=true" cargo test --lib test_aes_gcm_counter_blocks
[snip]
thread 'aead::aes::aes_gcm_tests::test_aes_gcm_counter_blocks_max' panicked at src\aead\aes.rs:157:25:
attempt to add with overflow
```
  • Loading branch information
briansmith committed Mar 6, 2025
1 parent c0b2e84 commit e60b593
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/aead/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,49 @@ mod tests {
Key::new(key, cpu::features()).unwrap()
}
}

// These AES-GCM-specific tests are here instead of in `aes_gcm` because
// `Counter`'s API isn't visible (enough) to aes_gcm.
#[cfg(test)]
mod aes_gcm_tests {
use super::{super::aes_gcm::MAX_IN_OUT_LEN, *};
use core::num::NonZeroU32;

#[test]
fn test_aes_gcm_counter_blocks_max() {
test_aes_gcm_counter_blocks(MAX_IN_OUT_LEN, &[0, 0, 0, 0]);
}

#[test]
fn test_aes_gcm_counter_blocks_max_minus_one() {
test_aes_gcm_counter_blocks(MAX_IN_OUT_LEN - BLOCK_LEN, &[0xff, 0xff, 0xff, 0xff]);
}

fn test_aes_gcm_counter_blocks(in_out_len: usize, expected_final_counter: &[u8; 4]) {
fn ctr32(ctr: &Counter) -> &[u8; 4] {
(&ctr.0[12..]).try_into().unwrap()
}

let rounded_down = in_out_len / BLOCK_LEN;
let blocks = rounded_down + (if in_out_len % BLOCK_LEN == 0 { 0 } else { 1 });
let blocks = u32::try_from(blocks)
.ok()
.and_then(NonZeroU32::new)
.unwrap();

let nonce = Nonce::assume_unique_for_key([1; 12]);
let mut ctr = Counter::one(nonce);
assert_eq!(ctr32(&ctr), &[0, 0, 0, 1]);
let _tag_iv = ctr.increment();
assert_eq!(ctr32(&ctr), &[0, 0, 0, 2]);
ctr.increment_by_less_safe(blocks);

// `MAX_IN_OUT_LEN` is less on 32-bit targets, so we don't even get
// close to wrapping, but run the tests on them anyway.
#[cfg(target_pointer_width = "64")]
assert_eq!(ctr32(&ctr), expected_final_counter);

#[cfg(target_pointer_width = "32")]
let _ = expected_final_counter;
}
}

0 comments on commit e60b593

Please sign in to comment.