Skip to content

Commit e60b593

Browse files
committed
aes_gcm: Add counter test for max input/output length.
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 ```
1 parent c0b2e84 commit e60b593

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

src/aead/aes.rs

+46
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,49 @@ mod tests {
236236
Key::new(key, cpu::features()).unwrap()
237237
}
238238
}
239+
240+
// These AES-GCM-specific tests are here instead of in `aes_gcm` because
241+
// `Counter`'s API isn't visible (enough) to aes_gcm.
242+
#[cfg(test)]
243+
mod aes_gcm_tests {
244+
use super::{super::aes_gcm::MAX_IN_OUT_LEN, *};
245+
use core::num::NonZeroU32;
246+
247+
#[test]
248+
fn test_aes_gcm_counter_blocks_max() {
249+
test_aes_gcm_counter_blocks(MAX_IN_OUT_LEN, &[0, 0, 0, 0]);
250+
}
251+
252+
#[test]
253+
fn test_aes_gcm_counter_blocks_max_minus_one() {
254+
test_aes_gcm_counter_blocks(MAX_IN_OUT_LEN - BLOCK_LEN, &[0xff, 0xff, 0xff, 0xff]);
255+
}
256+
257+
fn test_aes_gcm_counter_blocks(in_out_len: usize, expected_final_counter: &[u8; 4]) {
258+
fn ctr32(ctr: &Counter) -> &[u8; 4] {
259+
(&ctr.0[12..]).try_into().unwrap()
260+
}
261+
262+
let rounded_down = in_out_len / BLOCK_LEN;
263+
let blocks = rounded_down + (if in_out_len % BLOCK_LEN == 0 { 0 } else { 1 });
264+
let blocks = u32::try_from(blocks)
265+
.ok()
266+
.and_then(NonZeroU32::new)
267+
.unwrap();
268+
269+
let nonce = Nonce::assume_unique_for_key([1; 12]);
270+
let mut ctr = Counter::one(nonce);
271+
assert_eq!(ctr32(&ctr), &[0, 0, 0, 1]);
272+
let _tag_iv = ctr.increment();
273+
assert_eq!(ctr32(&ctr), &[0, 0, 0, 2]);
274+
ctr.increment_by_less_safe(blocks);
275+
276+
// `MAX_IN_OUT_LEN` is less on 32-bit targets, so we don't even get
277+
// close to wrapping, but run the tests on them anyway.
278+
#[cfg(target_pointer_width = "64")]
279+
assert_eq!(ctr32(&ctr), expected_final_counter);
280+
281+
#[cfg(target_pointer_width = "32")]
282+
let _ = expected_final_counter;
283+
}
284+
}

0 commit comments

Comments
 (0)