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