123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- // Copyright 2015-2016 Brian Smith.
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
- // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
- // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- #![cfg(any(not(target_arch = "wasm32"), feature = "wasm32_c"))]
- #[cfg(target_arch = "wasm32")]
- use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
- #[cfg(target_arch = "wasm32")]
- wasm_bindgen_test_configure!(run_in_browser);
- use core::ops::RangeFrom;
- use ring::{aead, error, test, test_file};
- #[test]
- #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
- fn aead_aes_gcm_128() {
- test_aead(
- &aead::AES_128_GCM,
- seal_with_key,
- open_with_key,
- test_file!("aead_aes_128_gcm_tests.txt"),
- );
- test_aead(
- &aead::AES_128_GCM,
- seal_with_less_safe_key,
- open_with_less_safe_key,
- test_file!("aead_aes_128_gcm_tests.txt"),
- );
- }
- #[test]
- #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
- fn aead_aes_gcm_256() {
- test_aead(
- &aead::AES_256_GCM,
- seal_with_key,
- open_with_key,
- test_file!("aead_aes_256_gcm_tests.txt"),
- );
- test_aead(
- &aead::AES_256_GCM,
- seal_with_less_safe_key,
- open_with_less_safe_key,
- test_file!("aead_aes_256_gcm_tests.txt"),
- );
- }
- #[cfg(any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "x86_64",
- target_arch = "x86"
- ))]
- #[test]
- fn aead_chacha20_poly1305() {
- test_aead(
- &aead::CHACHA20_POLY1305,
- seal_with_key,
- open_with_key,
- test_file!("aead_chacha20_poly1305_tests.txt"),
- );
- test_aead(
- &aead::CHACHA20_POLY1305,
- seal_with_less_safe_key,
- open_with_less_safe_key,
- test_file!("aead_chacha20_poly1305_tests.txt"),
- );
- }
- fn test_aead<Seal, Open>(
- aead_alg: &'static aead::Algorithm,
- seal: Seal,
- open: Open,
- test_file: test::File,
- ) where
- Seal: Fn(
- &'static aead::Algorithm,
- &[u8],
- aead::Nonce,
- aead::Aad<&[u8]>,
- &mut Vec<u8>,
- ) -> Result<(), error::Unspecified>,
- Open: for<'a> Fn(
- &'static aead::Algorithm,
- &[u8],
- aead::Nonce,
- aead::Aad<&[u8]>,
- &'a mut [u8],
- RangeFrom<usize>,
- ) -> Result<&'a mut [u8], error::Unspecified>,
- {
- test_aead_key_sizes(aead_alg);
- test::run(test_file, |section, test_case| {
- assert_eq!(section, "");
- let key_bytes = test_case.consume_bytes("KEY");
- let nonce_bytes = test_case.consume_bytes("NONCE");
- let plaintext = test_case.consume_bytes("IN");
- let aad = test_case.consume_bytes("AD");
- let mut ct = test_case.consume_bytes("CT");
- let tag = test_case.consume_bytes("TAG");
- let error = test_case.consume_optional_string("FAILS");
- match &error {
- Some(err) if err == "WRONG_NONCE_LENGTH" => {
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce_bytes).is_err());
- return Ok(());
- }
- _ => (),
- };
- let mut s_in_out = plaintext.clone();
- let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap();
- let s_result = seal(
- aead_alg,
- &key_bytes[..],
- nonce,
- aead::Aad::from(&aad[..]),
- &mut s_in_out,
- );
- ct.extend(tag);
- if s_result.is_ok() {
- assert_eq!(&ct, &s_in_out);
- }
- // In release builds, test all prefix lengths from 0 to 4096 bytes.
- // Debug builds are too slow for this, so for those builds, only
- // test a smaller subset.
- // TLS record headers are 5 bytes long.
- // TLS explicit nonces for AES-GCM are 8 bytes long.
- static MINIMAL_IN_PREFIX_LENS: [usize; 36] = [
- // No input prefix to overwrite; i.e. the opening is exactly
- // "in place."
- 0,
- 1,
- 2,
- // Proposed TLS 1.3 header (no explicit nonce).
- 5,
- 8,
- // Probably the most common use of a non-zero `in_prefix_len`
- // would be to write a decrypted TLS record over the top of the
- // TLS header and nonce.
- 5 /* record header */ + 8, /* explicit nonce */
- // The stitched AES-GCM x86-64 code works on 6-block (96 byte)
- // units. Some of the ChaCha20 code is even weirder.
- 15, // The maximum partial AES block.
- 16, // One AES block.
- 17, // One byte more than a full AES block.
- 31, // 2 AES blocks or 1 ChaCha20 block, minus 1.
- 32, // Two AES blocks, one ChaCha20 block.
- 33, // 2 AES blocks or 1 ChaCha20 block, plus 1.
- 47, // Three AES blocks - 1.
- 48, // Three AES blocks.
- 49, // Three AES blocks + 1.
- 63, // Four AES blocks or two ChaCha20 blocks, minus 1.
- 64, // Four AES blocks or two ChaCha20 blocks.
- 65, // Four AES blocks or two ChaCha20 blocks, plus 1.
- 79, // Five AES blocks, minus 1.
- 80, // Five AES blocks.
- 81, // Five AES blocks, plus 1.
- 95, // Six AES blocks or three ChaCha20 blocks, minus 1.
- 96, // Six AES blocks or three ChaCha20 blocks.
- 97, // Six AES blocks or three ChaCha20 blocks, plus 1.
- 111, // Seven AES blocks, minus 1.
- 112, // Seven AES blocks.
- 113, // Seven AES blocks, plus 1.
- 127, // Eight AES blocks or four ChaCha20 blocks, minus 1.
- 128, // Eight AES blocks or four ChaCha20 blocks.
- 129, // Eight AES blocks or four ChaCha20 blocks, plus 1.
- 143, // Nine AES blocks, minus 1.
- 144, // Nine AES blocks.
- 145, // Nine AES blocks, plus 1.
- 255, // 16 AES blocks or 8 ChaCha20 blocks, minus 1.
- 256, // 16 AES blocks or 8 ChaCha20 blocks.
- 257, // 16 AES blocks or 8 ChaCha20 blocks, plus 1.
- ];
- let mut more_comprehensive_in_prefix_lengths = [0; 4096];
- let in_prefix_lengths = if cfg!(debug_assertions) {
- &MINIMAL_IN_PREFIX_LENS[..]
- } else {
- #[allow(clippy::needless_range_loop)]
- for b in 0..more_comprehensive_in_prefix_lengths.len() {
- more_comprehensive_in_prefix_lengths[b] = b;
- }
- &more_comprehensive_in_prefix_lengths[..]
- };
- let mut o_in_out = vec![123u8; 4096];
- for &in_prefix_len in in_prefix_lengths.iter() {
- o_in_out.truncate(0);
- o_in_out.resize(in_prefix_len, 123);
- o_in_out.extend_from_slice(&ct[..]);
- let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap();
- let o_result = open(
- aead_alg,
- &key_bytes,
- nonce,
- aead::Aad::from(&aad[..]),
- &mut o_in_out,
- in_prefix_len..,
- );
- match error {
- None => {
- assert!(s_result.is_ok());
- assert_eq!(&plaintext[..], o_result.unwrap());
- }
- Some(ref error) if error == "WRONG_NONCE_LENGTH" => {
- assert_eq!(Err(error::Unspecified), s_result);
- assert_eq!(Err(error::Unspecified), o_result);
- }
- Some(error) => {
- unreachable!("Unexpected error test case: {}", error);
- }
- };
- }
- Ok(())
- });
- }
- fn seal_with_key(
- algorithm: &'static aead::Algorithm,
- key: &[u8],
- nonce: aead::Nonce,
- aad: aead::Aad<&[u8]>,
- in_out: &mut Vec<u8>,
- ) -> Result<(), error::Unspecified> {
- let mut s_key: aead::SealingKey<OneNonceSequence> = make_key(algorithm, key, nonce);
- s_key.seal_in_place_append_tag(aad, in_out)
- }
- fn open_with_key<'a>(
- algorithm: &'static aead::Algorithm,
- key: &[u8],
- nonce: aead::Nonce,
- aad: aead::Aad<&[u8]>,
- in_out: &'a mut [u8],
- ciphertext_and_tag: RangeFrom<usize>,
- ) -> Result<&'a mut [u8], error::Unspecified> {
- let mut o_key: aead::OpeningKey<OneNonceSequence> = make_key(algorithm, key, nonce);
- o_key.open_within(aad, in_out, ciphertext_and_tag)
- }
- fn seal_with_less_safe_key(
- algorithm: &'static aead::Algorithm,
- key: &[u8],
- nonce: aead::Nonce,
- aad: aead::Aad<&[u8]>,
- in_out: &mut Vec<u8>,
- ) -> Result<(), error::Unspecified> {
- let key = make_less_safe_key(algorithm, key);
- key.seal_in_place_append_tag(nonce, aad, in_out)
- }
- fn open_with_less_safe_key<'a>(
- algorithm: &'static aead::Algorithm,
- key: &[u8],
- nonce: aead::Nonce,
- aad: aead::Aad<&[u8]>,
- in_out: &'a mut [u8],
- ciphertext_and_tag: RangeFrom<usize>,
- ) -> Result<&'a mut [u8], error::Unspecified> {
- let key = make_less_safe_key(algorithm, key);
- key.open_within(nonce, aad, in_out, ciphertext_and_tag)
- }
- #[allow(clippy::range_plus_one)]
- fn test_aead_key_sizes(aead_alg: &'static aead::Algorithm) {
- let key_len = aead_alg.key_len();
- let key_data = vec![0u8; key_len * 2];
- // Key is the right size.
- assert!(aead::UnboundKey::new(aead_alg, &key_data[..key_len]).is_ok());
- // Key is one byte too small.
- assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len - 1)]).is_err());
- // Key is one byte too large.
- assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len + 1)]).is_err());
- // Key is half the required size.
- assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len / 2)]).is_err());
- // Key is twice the required size.
- assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len * 2)]).is_err());
- // Key is empty.
- assert!(aead::UnboundKey::new(aead_alg, &[]).is_err());
- // Key is one byte.
- assert!(aead::UnboundKey::new(aead_alg, &[0]).is_err());
- }
- // Test that we reject non-standard nonce sizes.
- #[allow(clippy::range_plus_one)]
- #[test]
- fn test_aead_nonce_sizes() -> Result<(), error::Unspecified> {
- let nonce_len = aead::NONCE_LEN;
- let nonce = vec![0u8; nonce_len * 2];
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..nonce_len]).is_ok());
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len - 1)]).is_err());
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len + 1)]).is_err());
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len / 2)]).is_err());
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len * 2)]).is_err());
- assert!(aead::Nonce::try_assume_unique_for_key(&[]).is_err());
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..1]).is_err());
- assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..16]).is_err()); // 128 bits.
- Ok(())
- }
- #[cfg(any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "x86_64",
- target_arch = "x86"
- ))]
- #[allow(clippy::range_plus_one)]
- #[test]
- fn aead_chacha20_poly1305_openssh() {
- // TODO: test_aead_key_sizes(...);
- test::run(
- test_file!("aead_chacha20_poly1305_openssh_tests.txt"),
- |section, test_case| {
- assert_eq!(section, "");
- // XXX: `polyfill::convert` isn't available here.
- let key_bytes = {
- let as_vec = test_case.consume_bytes("KEY");
- let mut as_array = [0u8; aead::chacha20_poly1305_openssh::KEY_LEN];
- as_array.copy_from_slice(&as_vec);
- as_array
- };
- let sequence_number = test_case.consume_usize("SEQUENCE_NUMBER");
- assert_eq!(sequence_number as u32 as usize, sequence_number);
- let sequence_num = sequence_number as u32;
- let plaintext = test_case.consume_bytes("IN");
- let ct = test_case.consume_bytes("CT");
- let expected_tag = test_case.consume_bytes("TAG");
- // TODO: Add some tests for when things fail.
- //let error = test_case.consume_optional_string("FAILS");
- let mut tag = [0u8; aead::chacha20_poly1305_openssh::TAG_LEN];
- let mut s_in_out = plaintext.clone();
- let s_key = aead::chacha20_poly1305_openssh::SealingKey::new(&key_bytes);
- s_key.seal_in_place(sequence_num, &mut s_in_out[..], &mut tag);
- assert_eq!(&ct, &s_in_out);
- assert_eq!(&expected_tag, &tag);
- let o_key = aead::chacha20_poly1305_openssh::OpeningKey::new(&key_bytes);
- {
- let o_result = o_key.open_in_place(sequence_num, &mut s_in_out[..], &tag);
- assert_eq!(o_result, Ok(&plaintext[4..]));
- }
- assert_eq!(&s_in_out[..4], &ct[..4]);
- assert_eq!(&s_in_out[4..], &plaintext[4..]);
- Ok(())
- },
- );
- }
- #[test]
- #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
- fn test_tag_traits() {
- test::compile_time_assert_send::<aead::Tag>();
- test::compile_time_assert_sync::<aead::Tag>();
- }
- #[test]
- #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
- fn test_aead_key_debug() {
- let key_bytes = [0; 32];
- let nonce = [0; aead::NONCE_LEN];
- let key = aead::UnboundKey::new(&aead::AES_256_GCM, &key_bytes).unwrap();
- assert_eq!(
- "UnboundKey { algorithm: AES_256_GCM }",
- format!("{:?}", key)
- );
- let sealing_key: aead::SealingKey<OneNonceSequence> = make_key(
- &aead::AES_256_GCM,
- &key_bytes,
- aead::Nonce::try_assume_unique_for_key(&nonce).unwrap(),
- );
- assert_eq!(
- "SealingKey { algorithm: AES_256_GCM }",
- format!("{:?}", sealing_key)
- );
- let opening_key: aead::OpeningKey<OneNonceSequence> = make_key(
- &aead::AES_256_GCM,
- &key_bytes,
- aead::Nonce::try_assume_unique_for_key(&nonce).unwrap(),
- );
- assert_eq!(
- "OpeningKey { algorithm: AES_256_GCM }",
- format!("{:?}", opening_key)
- );
- let key: aead::LessSafeKey = make_less_safe_key(&aead::AES_256_GCM, &key_bytes);
- assert_eq!(
- "LessSafeKey { algorithm: AES_256_GCM }",
- format!("{:?}", key)
- );
- }
- fn make_key<K: aead::BoundKey<OneNonceSequence>>(
- algorithm: &'static aead::Algorithm,
- key: &[u8],
- nonce: aead::Nonce,
- ) -> K {
- let key = aead::UnboundKey::new(algorithm, key).unwrap();
- let nonce_sequence = OneNonceSequence::new(nonce);
- K::new(key, nonce_sequence)
- }
- fn make_less_safe_key(algorithm: &'static aead::Algorithm, key: &[u8]) -> aead::LessSafeKey {
- let key = aead::UnboundKey::new(algorithm, key).unwrap();
- aead::LessSafeKey::new(key)
- }
- struct OneNonceSequence(Option<aead::Nonce>);
- impl OneNonceSequence {
- /// Constructs the sequence allowing `advance()` to be called
- /// `allowed_invocations` times.
- fn new(nonce: aead::Nonce) -> Self {
- Self(Some(nonce))
- }
- }
- impl aead::NonceSequence for OneNonceSequence {
- fn advance(&mut self) -> Result<aead::Nonce, error::Unspecified> {
- self.0.take().ok_or(error::Unspecified)
- }
- }
|