1 // Copyright 2015-2021 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 #[cfg(target_arch = "wasm32")]
16 use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
17 
18 #[cfg(target_arch = "wasm32")]
19 wasm_bindgen_test_configure!(run_in_browser);
20 
21 use core::ops::RangeFrom;
22 use ring::{aead, error, test, test_file};
23 
24 /// Generate the known answer test functions for the given algorithm and test
25 /// case input file, where each test is implemented by a test in `$test`.
26 ///
27 /// All of these tests can be run in parallel.
28 macro_rules! test_known_answer {
29     ( $alg:ident, $test_file:expr, [ $( $test:ident ),+, ] ) => {
30         $(
31             #[test]
32             fn $test() {
33                 test_aead(
34                     &aead::$alg,
35                     super::super::$test,
36                     test_file!($test_file));
37             }
38         )+
39     }
40 }
41 
42 /// Generate the tests for a given algorithm.
43 ///
44 /// All of these tests can be run in parallel.
45 macro_rules! test_aead {
46     { $( { $alg:ident, $test_file:expr } ),+, } => {
47         mod aead_test { // Make `cargo test aead` include these files.
48             $(
49                 #[allow(non_snake_case)]
50                 mod $alg { // Provide a separate namespace for each algorithm's test.
51                     #[cfg(not(target_arch = "wasm32"))]
52                     use super::super::*;
53 
54                     #[cfg(target_arch = "wasm32")]
55                     use super::super::{*, test};
56 
57                     test_known_answer!(
58                         $alg,
59                         $test_file,
60                         [
61                             less_safe_key_open_in_place,
62                             less_safe_key_open_within,
63                             less_safe_key_seal_in_place_append_tag,
64                             less_safe_key_seal_in_place_separate_tag,
65                             opening_key_open_in_place,
66                             opening_key_open_within,
67                             sealing_key_seal_in_place_append_tag,
68                             sealing_key_seal_in_place_separate_tag,
69                             test_open_in_place_seperate_tag,
70                         ]);
71 
72                     #[test]
73                     fn key_sizes() {
74                         super::super::key_sizes(&aead::$alg);
75                     }
76                 }
77             )+
78         }
79     }
80 }
81 
82 test_aead! {
83     { AES_128_GCM, "aead_aes_128_gcm_tests.txt" },
84     { AES_256_GCM, "aead_aes_256_gcm_tests.txt" },
85     { CHACHA20_POLY1305, "aead_chacha20_poly1305_tests.txt" },
86 }
87 
88 struct KnownAnswerTestCase<'a> {
89     key: &'a [u8],
90     nonce: [u8; aead::NONCE_LEN],
91     plaintext: &'a [u8],
92     aad: aead::Aad<&'a [u8]>,
93     ciphertext: &'a [u8],
94     tag: &'a [u8],
95 }
96 
test_aead( aead_alg: &'static aead::Algorithm, f: impl Fn(&'static aead::Algorithm, KnownAnswerTestCase) -> Result<(), error::Unspecified>, test_file: test::File, )97 fn test_aead(
98     aead_alg: &'static aead::Algorithm,
99     f: impl Fn(&'static aead::Algorithm, KnownAnswerTestCase) -> Result<(), error::Unspecified>,
100     test_file: test::File,
101 ) {
102     test::run(test_file, |section, test_case| {
103         assert_eq!(section, "");
104         let key = test_case.consume_bytes("KEY");
105         let nonce = test_case.consume_bytes("NONCE");
106         let plaintext = test_case.consume_bytes("IN");
107         let aad = test_case.consume_bytes("AD");
108         let ct = test_case.consume_bytes("CT");
109         let tag = test_case.consume_bytes("TAG");
110         let error = test_case.consume_optional_string("FAILS");
111 
112         match error.as_deref() {
113             Some("WRONG_NONCE_LENGTH") => {
114                 assert!(matches!(
115                     aead::Nonce::try_assume_unique_for_key(&nonce),
116                     Err(error::Unspecified)
117                 ));
118                 return Ok(());
119             }
120             Some(unexpected) => {
121                 unreachable!("unexpected error in test data: {}", unexpected);
122             }
123             None => {}
124         };
125 
126         let test_case = KnownAnswerTestCase {
127             key: &key,
128             nonce: nonce.as_slice().try_into().unwrap(),
129             plaintext: &plaintext,
130             aad: aead::Aad::from(&aad),
131             ciphertext: &ct,
132             tag: &tag,
133         };
134 
135         f(aead_alg, test_case)
136     })
137 }
138 
test_seal_append_tag<Seal>( tc: &KnownAnswerTestCase, seal: Seal, ) -> Result<(), error::Unspecified> where Seal: FnOnce(aead::Nonce, &mut Vec<u8>) -> Result<(), error::Unspecified>,139 fn test_seal_append_tag<Seal>(
140     tc: &KnownAnswerTestCase,
141     seal: Seal,
142 ) -> Result<(), error::Unspecified>
143 where
144     Seal: FnOnce(aead::Nonce, &mut Vec<u8>) -> Result<(), error::Unspecified>,
145 {
146     let mut in_out = Vec::from(tc.plaintext);
147     seal(aead::Nonce::assume_unique_for_key(tc.nonce), &mut in_out)?;
148 
149     let mut expected_ciphertext_and_tag = Vec::from(tc.ciphertext);
150     expected_ciphertext_and_tag.extend_from_slice(tc.tag);
151 
152     assert_eq!(in_out, expected_ciphertext_and_tag);
153 
154     Ok(())
155 }
156 
test_seal_separate_tag<Seal>( tc: &KnownAnswerTestCase, seal: Seal, ) -> Result<(), error::Unspecified> where Seal: Fn(aead::Nonce, &mut [u8]) -> Result<aead::Tag, error::Unspecified>,157 fn test_seal_separate_tag<Seal>(
158     tc: &KnownAnswerTestCase,
159     seal: Seal,
160 ) -> Result<(), error::Unspecified>
161 where
162     Seal: Fn(aead::Nonce, &mut [u8]) -> Result<aead::Tag, error::Unspecified>,
163 {
164     let mut in_out = Vec::from(tc.plaintext);
165     let actual_tag = seal(aead::Nonce::assume_unique_for_key(tc.nonce), &mut in_out)?;
166     assert_eq!(actual_tag.as_ref(), tc.tag);
167     assert_eq!(in_out, tc.ciphertext);
168 
169     Ok(())
170 }
171 
test_open_in_place<OpenInPlace>( tc: &KnownAnswerTestCase<'_>, open_in_place: OpenInPlace, ) -> Result<(), error::Unspecified> where OpenInPlace: for<'a> FnOnce(aead::Nonce, &'a mut [u8]) -> Result<&'a mut [u8], error::Unspecified>,172 fn test_open_in_place<OpenInPlace>(
173     tc: &KnownAnswerTestCase<'_>,
174     open_in_place: OpenInPlace,
175 ) -> Result<(), error::Unspecified>
176 where
177     OpenInPlace:
178         for<'a> FnOnce(aead::Nonce, &'a mut [u8]) -> Result<&'a mut [u8], error::Unspecified>,
179 {
180     let nonce = aead::Nonce::assume_unique_for_key(tc.nonce);
181 
182     let mut in_out = Vec::from(tc.ciphertext);
183     in_out.extend_from_slice(tc.tag);
184 
185     let actual_plaintext = open_in_place(nonce, &mut in_out)?;
186 
187     assert_eq!(actual_plaintext, tc.plaintext);
188     assert_eq!(&in_out[..tc.plaintext.len()], tc.plaintext);
189     Ok(())
190 }
191 
test_open_in_place_seperate_tag( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>192 fn test_open_in_place_seperate_tag(
193     alg: &'static aead::Algorithm,
194     tc: KnownAnswerTestCase,
195 ) -> Result<(), error::Unspecified> {
196     let key = make_less_safe_key(alg, tc.key);
197 
198     let mut in_out = Vec::from(tc.ciphertext);
199     let tag = tc.tag.try_into().unwrap();
200 
201     // Test the simplest behavior.
202     {
203         let nonce = aead::Nonce::assume_unique_for_key(tc.nonce);
204         let actual_plaintext =
205             key.open_in_place_separate_tag(nonce, tc.aad, tag, &mut in_out, 0..)?;
206 
207         assert_eq!(actual_plaintext, tc.plaintext);
208         assert_eq!(&in_out[..tc.plaintext.len()], tc.plaintext);
209     }
210 
211     // Test that ciphertext range shifing works as expected.
212     {
213         let range = in_out.len()..;
214         in_out.extend_from_slice(tc.ciphertext);
215 
216         let nonce = aead::Nonce::assume_unique_for_key(tc.nonce);
217         let actual_plaintext =
218             key.open_in_place_separate_tag(nonce, tc.aad, tag, &mut in_out, range)?;
219 
220         assert_eq!(actual_plaintext, tc.plaintext);
221         assert_eq!(&in_out[..tc.plaintext.len()], tc.plaintext);
222     }
223 
224     Ok(())
225 }
226 
test_open_within<OpenWithin>( tc: &KnownAnswerTestCase<'_>, open_within: OpenWithin, ) -> Result<(), error::Unspecified> where OpenWithin: for<'a> Fn( aead::Nonce, &'a mut [u8], RangeFrom<usize>, ) -> Result<&'a mut [u8], error::Unspecified>,227 fn test_open_within<OpenWithin>(
228     tc: &KnownAnswerTestCase<'_>,
229     open_within: OpenWithin,
230 ) -> Result<(), error::Unspecified>
231 where
232     OpenWithin: for<'a> Fn(
233         aead::Nonce,
234         &'a mut [u8],
235         RangeFrom<usize>,
236     ) -> Result<&'a mut [u8], error::Unspecified>,
237 {
238     // In release builds, test all prefix lengths from 0 to 4096 bytes.
239     // Debug builds are too slow for this, so for those builds, only
240     // test a smaller subset.
241 
242     // TLS record headers are 5 bytes long.
243     // TLS explicit nonces for AES-GCM are 8 bytes long.
244     static MINIMAL_IN_PREFIX_LENS: [usize; 36] = [
245         // No input prefix to overwrite; i.e. the opening is exactly
246         // "in place."
247         0,
248         1,
249         2,
250         // Proposed TLS 1.3 header (no explicit nonce).
251         5,
252         8,
253         // Probably the most common use of a non-zero `in_prefix_len`
254         // would be to write a decrypted TLS record over the top of the
255         // TLS header and nonce.
256         5 /* record header */ + 8, /* explicit nonce */
257         // The stitched AES-GCM x86-64 code works on 6-block (96 byte)
258         // units. Some of the ChaCha20 code is even weirder.
259         15,  // The maximum partial AES block.
260         16,  // One AES block.
261         17,  // One byte more than a full AES block.
262         31,  // 2 AES blocks or 1 ChaCha20 block, minus 1.
263         32,  // Two AES blocks, one ChaCha20 block.
264         33,  // 2 AES blocks or 1 ChaCha20 block, plus 1.
265         47,  // Three AES blocks - 1.
266         48,  // Three AES blocks.
267         49,  // Three AES blocks + 1.
268         63,  // Four AES blocks or two ChaCha20 blocks, minus 1.
269         64,  // Four AES blocks or two ChaCha20 blocks.
270         65,  // Four AES blocks or two ChaCha20 blocks, plus 1.
271         79,  // Five AES blocks, minus 1.
272         80,  // Five AES blocks.
273         81,  // Five AES blocks, plus 1.
274         95,  // Six AES blocks or three ChaCha20 blocks, minus 1.
275         96,  // Six AES blocks or three ChaCha20 blocks.
276         97,  // Six AES blocks or three ChaCha20 blocks, plus 1.
277         111, // Seven AES blocks, minus 1.
278         112, // Seven AES blocks.
279         113, // Seven AES blocks, plus 1.
280         127, // Eight AES blocks or four ChaCha20 blocks, minus 1.
281         128, // Eight AES blocks or four ChaCha20 blocks.
282         129, // Eight AES blocks or four ChaCha20 blocks, plus 1.
283         143, // Nine AES blocks, minus 1.
284         144, // Nine AES blocks.
285         145, // Nine AES blocks, plus 1.
286         255, // 16 AES blocks or 8 ChaCha20 blocks, minus 1.
287         256, // 16 AES blocks or 8 ChaCha20 blocks.
288         257, // 16 AES blocks or 8 ChaCha20 blocks, plus 1.
289     ];
290 
291     let mut more_comprehensive_in_prefix_lengths = [0; 4096];
292     let in_prefix_lengths = if cfg!(debug_assertions) {
293         &MINIMAL_IN_PREFIX_LENS[..]
294     } else {
295         #[allow(clippy::needless_range_loop)]
296         for b in 0..more_comprehensive_in_prefix_lengths.len() {
297             more_comprehensive_in_prefix_lengths[b] = b;
298         }
299         &more_comprehensive_in_prefix_lengths[..]
300     };
301     let mut in_out = vec![123u8; 4096];
302 
303     for &in_prefix_len in in_prefix_lengths.iter() {
304         in_out.truncate(0);
305         in_out.resize(in_prefix_len, 123);
306         in_out.extend_from_slice(tc.ciphertext);
307         in_out.extend_from_slice(tc.tag);
308 
309         let actual_plaintext = open_within(
310             aead::Nonce::assume_unique_for_key(tc.nonce),
311             &mut in_out,
312             in_prefix_len..,
313         )?;
314         assert_eq!(actual_plaintext, tc.plaintext);
315         assert_eq!(&in_out[..tc.plaintext.len()], tc.plaintext);
316     }
317 
318     Ok(())
319 }
320 
sealing_key_seal_in_place_append_tag( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>321 fn sealing_key_seal_in_place_append_tag(
322     alg: &'static aead::Algorithm,
323     tc: KnownAnswerTestCase,
324 ) -> Result<(), error::Unspecified> {
325     test_seal_append_tag(&tc, |nonce, in_out| {
326         let mut key: aead::SealingKey<OneNonceSequence> = make_key(alg, tc.key, nonce);
327         key.seal_in_place_append_tag(tc.aad, in_out)
328     })
329 }
330 
sealing_key_seal_in_place_separate_tag( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>331 fn sealing_key_seal_in_place_separate_tag(
332     alg: &'static aead::Algorithm,
333     tc: KnownAnswerTestCase,
334 ) -> Result<(), error::Unspecified> {
335     test_seal_separate_tag(&tc, |nonce, in_out| {
336         let mut key: aead::SealingKey<_> = make_key(alg, tc.key, nonce);
337         key.seal_in_place_separate_tag(tc.aad, in_out)
338     })
339 }
340 
opening_key_open_in_place( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>341 fn opening_key_open_in_place(
342     alg: &'static aead::Algorithm,
343     tc: KnownAnswerTestCase,
344 ) -> Result<(), error::Unspecified> {
345     test_open_in_place(&tc, |nonce, in_out| {
346         let mut key: aead::OpeningKey<_> = make_key(alg, tc.key, nonce);
347         key.open_in_place(tc.aad, in_out)
348     })
349 }
350 
opening_key_open_within( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>351 fn opening_key_open_within(
352     alg: &'static aead::Algorithm,
353     tc: KnownAnswerTestCase,
354 ) -> Result<(), error::Unspecified> {
355     test_open_within(&tc, |nonce, in_out, ciphertext_and_tag| {
356         let mut key: aead::OpeningKey<OneNonceSequence> = make_key(alg, tc.key, nonce);
357         key.open_within(tc.aad, in_out, ciphertext_and_tag)
358     })
359 }
360 
less_safe_key_seal_in_place_append_tag( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>361 fn less_safe_key_seal_in_place_append_tag(
362     alg: &'static aead::Algorithm,
363     tc: KnownAnswerTestCase,
364 ) -> Result<(), error::Unspecified> {
365     test_seal_append_tag(&tc, |nonce, in_out| {
366         let key = make_less_safe_key(alg, tc.key);
367         key.seal_in_place_append_tag(nonce, tc.aad, in_out)
368     })
369 }
370 
less_safe_key_open_in_place( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>371 fn less_safe_key_open_in_place(
372     alg: &'static aead::Algorithm,
373     tc: KnownAnswerTestCase,
374 ) -> Result<(), error::Unspecified> {
375     test_open_in_place(&tc, |nonce, in_out| {
376         let key = make_less_safe_key(alg, tc.key);
377         key.open_in_place(nonce, tc.aad, in_out)
378     })
379 }
380 
less_safe_key_seal_in_place_separate_tag( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>381 fn less_safe_key_seal_in_place_separate_tag(
382     alg: &'static aead::Algorithm,
383     tc: KnownAnswerTestCase,
384 ) -> Result<(), error::Unspecified> {
385     test_seal_separate_tag(&tc, |nonce, in_out| {
386         let key = make_less_safe_key(alg, tc.key);
387         key.seal_in_place_separate_tag(nonce, tc.aad, in_out)
388     })
389 }
390 
less_safe_key_open_within( alg: &'static aead::Algorithm, tc: KnownAnswerTestCase, ) -> Result<(), error::Unspecified>391 fn less_safe_key_open_within(
392     alg: &'static aead::Algorithm,
393     tc: KnownAnswerTestCase,
394 ) -> Result<(), error::Unspecified> {
395     test_open_within(&tc, |nonce, in_out, ciphertext_and_tag| {
396         let key = make_less_safe_key(alg, tc.key);
397         key.open_within(nonce, tc.aad, in_out, ciphertext_and_tag)
398     })
399 }
400 
401 #[allow(clippy::range_plus_one)]
key_sizes(aead_alg: &'static aead::Algorithm)402 fn key_sizes(aead_alg: &'static aead::Algorithm) {
403     let key_len = aead_alg.key_len();
404     let key_data = vec![0u8; key_len * 2];
405 
406     // Key is the right size.
407     assert!(aead::UnboundKey::new(aead_alg, &key_data[..key_len]).is_ok());
408 
409     // Key is one byte too small.
410     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len - 1)]).is_err());
411 
412     // Key is one byte too large.
413     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len + 1)]).is_err());
414 
415     // Key is half the required size.
416     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len / 2)]).is_err());
417 
418     // Key is twice the required size.
419     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len * 2)]).is_err());
420 
421     // Key is empty.
422     assert!(aead::UnboundKey::new(aead_alg, &[]).is_err());
423 
424     // Key is one byte.
425     assert!(aead::UnboundKey::new(aead_alg, &[0]).is_err());
426 }
427 
428 // Test that we reject non-standard nonce sizes.
429 #[allow(clippy::range_plus_one)]
430 #[test]
test_aead_nonce_sizes()431 fn test_aead_nonce_sizes() {
432     let nonce_len = aead::NONCE_LEN;
433     let nonce = vec![0u8; nonce_len * 2];
434 
435     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..nonce_len]).is_ok());
436     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len - 1)]).is_err());
437     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len + 1)]).is_err());
438     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len / 2)]).is_err());
439     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len * 2)]).is_err());
440     assert!(aead::Nonce::try_assume_unique_for_key(&[]).is_err());
441     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..1]).is_err());
442     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..16]).is_err()); // 128 bits.
443 }
444 
445 #[allow(clippy::range_plus_one)]
446 #[test]
aead_chacha20_poly1305_openssh()447 fn aead_chacha20_poly1305_openssh() {
448     // TODO: test_aead_key_sizes(...);
449 
450     test::run(
451         test_file!("aead_chacha20_poly1305_openssh_tests.txt"),
452         |section, test_case| {
453             assert_eq!(section, "");
454 
455             // XXX: `polyfill::convert` isn't available here.
456             let key_bytes = {
457                 let as_vec = test_case.consume_bytes("KEY");
458                 let mut as_array = [0u8; aead::chacha20_poly1305_openssh::KEY_LEN];
459                 as_array.copy_from_slice(&as_vec);
460                 as_array
461             };
462 
463             let sequence_number = test_case.consume_usize("SEQUENCE_NUMBER");
464             assert_eq!(sequence_number as u32 as usize, sequence_number);
465             let sequence_num = sequence_number as u32;
466             let plaintext = test_case.consume_bytes("IN");
467             let ct = test_case.consume_bytes("CT");
468             let expected_tag = test_case.consume_bytes("TAG");
469 
470             // TODO: Add some tests for when things fail.
471             //let error = test_case.consume_optional_string("FAILS");
472 
473             let mut tag = [0u8; aead::chacha20_poly1305_openssh::TAG_LEN];
474             let mut s_in_out = plaintext.clone();
475             let s_key = aead::chacha20_poly1305_openssh::SealingKey::new(&key_bytes);
476             s_key.seal_in_place(sequence_num, &mut s_in_out[..], &mut tag);
477             assert_eq!(&ct, &s_in_out);
478             assert_eq!(&expected_tag, &tag);
479             let o_key = aead::chacha20_poly1305_openssh::OpeningKey::new(&key_bytes);
480 
481             {
482                 let o_result = o_key.open_in_place(sequence_num, &mut s_in_out[..], &tag);
483                 assert_eq!(o_result, Ok(&plaintext[4..]));
484             }
485             assert_eq!(&s_in_out[..4], &ct[..4]);
486             assert_eq!(&s_in_out[4..], &plaintext[4..]);
487 
488             Ok(())
489         },
490     );
491 }
492 
493 #[test]
aead_test_aad_traits()494 fn aead_test_aad_traits() {
495     test::compile_time_assert_copy::<aead::Aad<&'_ [u8]>>();
496     test::compile_time_assert_eq::<aead::Aad<Vec<u8>>>(); // `!Copy`
497 
498     let aad_123 = aead::Aad::from(vec![1, 2, 3]); // `!Copy`
499     assert_eq!(aad_123, aad_123.clone()); // Cover `Clone` and `PartialEq`
500     assert_eq!(
501         format!("{:?}", aead::Aad::from(&[1, 2, 3])),
502         "Aad([1, 2, 3])"
503     );
504 }
505 
506 #[test]
test_tag_traits()507 fn test_tag_traits() {
508     test::compile_time_assert_send::<aead::Tag>();
509     test::compile_time_assert_sync::<aead::Tag>();
510 
511     test::compile_time_assert_copy::<aead::Tag>();
512     test::compile_time_assert_clone::<aead::Tag>();
513 
514     let tag = aead::Tag::from([4u8; 16]);
515     let _tag_2 = tag; // Cover `Copy`
516     assert_eq!(tag.as_ref(), tag.clone().as_ref()); // Cover `Clone`
517 }
518 
519 #[test]
test_aead_key_debug()520 fn test_aead_key_debug() {
521     let key_bytes = [0; 32];
522     let nonce = [0; aead::NONCE_LEN];
523 
524     let key = aead::UnboundKey::new(&aead::AES_256_GCM, &key_bytes).unwrap();
525     assert_eq!(
526         "UnboundKey { algorithm: AES_256_GCM }",
527         format!("{:?}", key)
528     );
529 
530     let sealing_key: aead::SealingKey<OneNonceSequence> = make_key(
531         &aead::AES_256_GCM,
532         &key_bytes,
533         aead::Nonce::try_assume_unique_for_key(&nonce).unwrap(),
534     );
535     assert_eq!(
536         "SealingKey { algorithm: AES_256_GCM }",
537         format!("{:?}", sealing_key)
538     );
539 
540     let opening_key: aead::OpeningKey<OneNonceSequence> = make_key(
541         &aead::AES_256_GCM,
542         &key_bytes,
543         aead::Nonce::try_assume_unique_for_key(&nonce).unwrap(),
544     );
545     assert_eq!(
546         "OpeningKey { algorithm: AES_256_GCM }",
547         format!("{:?}", opening_key)
548     );
549 
550     let key: aead::LessSafeKey = make_less_safe_key(&aead::AES_256_GCM, &key_bytes);
551     assert_eq!(
552         "LessSafeKey { algorithm: AES_256_GCM }",
553         format!("{:?}", key)
554     );
555 }
556 
test_aead_lesssafekey_clone_for_algorithm(algorithm: &'static aead::Algorithm)557 fn test_aead_lesssafekey_clone_for_algorithm(algorithm: &'static aead::Algorithm) {
558     let test_bytes: Vec<u8> = (0..32).collect();
559     let key_bytes = &test_bytes[..algorithm.key_len()];
560     let nonce_bytes = &test_bytes[..algorithm.nonce_len()];
561 
562     let key1: aead::LessSafeKey =
563         aead::LessSafeKey::new(aead::UnboundKey::new(algorithm, key_bytes).unwrap());
564     let key2 = key1.clone();
565 
566     // LessSafeKey doesn't support AsRef or PartialEq, so instead just check that both keys produce
567     // the same encrypted output.
568     let mut buf1: Vec<u8> = (0..100).collect();
569     let mut buf2 = buf1.clone();
570     let tag1 = key1
571         .seal_in_place_separate_tag(
572             aead::Nonce::try_assume_unique_for_key(nonce_bytes).unwrap(),
573             aead::Aad::empty(),
574             &mut buf1,
575         )
576         .unwrap();
577     let tag2 = key2
578         .seal_in_place_separate_tag(
579             aead::Nonce::try_assume_unique_for_key(nonce_bytes).unwrap(),
580             aead::Aad::empty(),
581             &mut buf2,
582         )
583         .unwrap();
584     assert_eq!(tag1.as_ref(), tag2.as_ref());
585     assert_eq!(buf1, buf2);
586 }
587 
588 #[test]
test_aead_lesssafekey_clone_aes_128_gcm()589 fn test_aead_lesssafekey_clone_aes_128_gcm() {
590     test_aead_lesssafekey_clone_for_algorithm(&aead::AES_128_GCM);
591 }
592 
593 #[test]
test_aead_lesssafekey_clone_aes_256_gcm()594 fn test_aead_lesssafekey_clone_aes_256_gcm() {
595     test_aead_lesssafekey_clone_for_algorithm(&aead::AES_256_GCM);
596 }
597 
598 #[test]
test_aead_lesssafekey_clone_chacha20_poly1305()599 fn test_aead_lesssafekey_clone_chacha20_poly1305() {
600     test_aead_lesssafekey_clone_for_algorithm(&aead::CHACHA20_POLY1305);
601 }
602 
make_key<K: aead::BoundKey<OneNonceSequence>>( algorithm: &'static aead::Algorithm, key: &[u8], nonce: aead::Nonce, ) -> K603 fn make_key<K: aead::BoundKey<OneNonceSequence>>(
604     algorithm: &'static aead::Algorithm,
605     key: &[u8],
606     nonce: aead::Nonce,
607 ) -> K {
608     let key = aead::UnboundKey::new(algorithm, key).unwrap();
609     let nonce_sequence = OneNonceSequence::new(nonce);
610     K::new(key, nonce_sequence)
611 }
612 
make_less_safe_key(algorithm: &'static aead::Algorithm, key: &[u8]) -> aead::LessSafeKey613 fn make_less_safe_key(algorithm: &'static aead::Algorithm, key: &[u8]) -> aead::LessSafeKey {
614     let key = aead::UnboundKey::new(algorithm, key).unwrap();
615     aead::LessSafeKey::new(key)
616 }
617 
618 struct OneNonceSequence(Option<aead::Nonce>);
619 
620 impl OneNonceSequence {
621     /// Constructs the sequence allowing `advance()` to be called
622     /// `allowed_invocations` times.
new(nonce: aead::Nonce) -> Self623     fn new(nonce: aead::Nonce) -> Self {
624         Self(Some(nonce))
625     }
626 }
627 
628 impl aead::NonceSequence for OneNonceSequence {
advance(&mut self) -> Result<aead::Nonce, error::Unspecified>629     fn advance(&mut self) -> Result<aead::Nonce, error::Unspecified> {
630         self.0.take().ok_or(error::Unspecified)
631     }
632 }
633