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 #![forbid(
16     anonymous_parameters,
17     box_pointers,
18     missing_copy_implementations,
19     missing_debug_implementations,
20     missing_docs,
21     trivial_casts,
22     trivial_numeric_casts,
23     unsafe_code,
24     unstable_features,
25     unused_extern_crates,
26     unused_import_braces,
27     unused_qualifications,
28     unused_results,
29     variant_size_differences,
30     warnings
31 )]
32 
33 use core::ops::RangeFrom;
34 use ring::{aead, error, test, test_file};
35 
36 #[test]
aead_aes_gcm_128()37 fn aead_aes_gcm_128() {
38     test_aead(
39         &aead::AES_128_GCM,
40         seal_with_key,
41         open_with_key,
42         test_file!("aead_aes_128_gcm_tests.txt"),
43     );
44     test_aead(
45         &aead::AES_128_GCM,
46         seal_with_less_safe_key,
47         open_with_less_safe_key,
48         test_file!("aead_aes_128_gcm_tests.txt"),
49     );
50 }
51 
52 #[test]
aead_aes_gcm_256()53 fn aead_aes_gcm_256() {
54     test_aead(
55         &aead::AES_256_GCM,
56         seal_with_key,
57         open_with_key,
58         test_file!("aead_aes_256_gcm_tests.txt"),
59     );
60     test_aead(
61         &aead::AES_256_GCM,
62         seal_with_less_safe_key,
63         open_with_less_safe_key,
64         test_file!("aead_aes_256_gcm_tests.txt"),
65     );
66 }
67 
68 #[test]
aead_chacha20_poly1305()69 fn aead_chacha20_poly1305() {
70     test_aead(
71         &aead::CHACHA20_POLY1305,
72         seal_with_key,
73         open_with_key,
74         test_file!("aead_chacha20_poly1305_tests.txt"),
75     );
76     test_aead(
77         &aead::CHACHA20_POLY1305,
78         seal_with_less_safe_key,
79         open_with_less_safe_key,
80         test_file!("aead_chacha20_poly1305_tests.txt"),
81     );
82 }
83 
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>,84 fn test_aead<Seal, Open>(
85     aead_alg: &'static aead::Algorithm,
86     seal: Seal,
87     open: Open,
88     test_file: test::File,
89 ) where
90     Seal: Fn(
91         &'static aead::Algorithm,
92         &[u8],
93         aead::Nonce,
94         aead::Aad<&[u8]>,
95         &mut Vec<u8>,
96     ) -> Result<(), error::Unspecified>,
97     Open: for<'a> Fn(
98         &'static aead::Algorithm,
99         &[u8],
100         aead::Nonce,
101         aead::Aad<&[u8]>,
102         &'a mut [u8],
103         RangeFrom<usize>,
104     ) -> Result<&'a mut [u8], error::Unspecified>,
105 {
106     test_aead_key_sizes(aead_alg);
107 
108     test::run(test_file, |section, test_case| {
109         assert_eq!(section, "");
110         let key_bytes = test_case.consume_bytes("KEY");
111         let nonce_bytes = test_case.consume_bytes("NONCE");
112         let plaintext = test_case.consume_bytes("IN");
113         let aad = test_case.consume_bytes("AD");
114         let mut ct = test_case.consume_bytes("CT");
115         let tag = test_case.consume_bytes("TAG");
116         let error = test_case.consume_optional_string("FAILS");
117 
118         match &error {
119             Some(err) if err == "WRONG_NONCE_LENGTH" => {
120                 assert!(aead::Nonce::try_assume_unique_for_key(&nonce_bytes).is_err());
121                 return Ok(());
122             }
123             _ => (),
124         };
125 
126         let mut s_in_out = plaintext.clone();
127         let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap();
128         let s_result = seal(
129             aead_alg,
130             &key_bytes[..],
131             nonce,
132             aead::Aad::from(&aad[..]),
133             &mut s_in_out,
134         );
135 
136         ct.extend(tag);
137 
138         if s_result.is_ok() {
139             assert_eq!(&ct, &s_in_out);
140         }
141 
142         // In release builds, test all prefix lengths from 0 to 4096 bytes.
143         // Debug builds are too slow for this, so for those builds, only
144         // test a smaller subset.
145 
146         // TLS record headers are 5 bytes long.
147         // TLS explicit nonces for AES-GCM are 8 bytes long.
148         static MINIMAL_IN_PREFIX_LENS: [usize; 36] = [
149             // No input prefix to overwrite; i.e. the opening is exactly
150             // "in place."
151             0,
152             1,
153             2,
154             // Proposed TLS 1.3 header (no explicit nonce).
155             5,
156             8,
157             // Probably the most common use of a non-zero `in_prefix_len`
158             // would be to write a decrypted TLS record over the top of the
159             // TLS header and nonce.
160             5 /* record header */ + 8, /* explicit nonce */
161             // The stitched AES-GCM x86-64 code works on 6-block (96 byte)
162             // units. Some of the ChaCha20 code is even weirder.
163             15,  // The maximum partial AES block.
164             16,  // One AES block.
165             17,  // One byte more than a full AES block.
166             31,  // 2 AES blocks or 1 ChaCha20 block, minus 1.
167             32,  // Two AES blocks, one ChaCha20 block.
168             33,  // 2 AES blocks or 1 ChaCha20 block, plus 1.
169             47,  // Three AES blocks - 1.
170             48,  // Three AES blocks.
171             49,  // Three AES blocks + 1.
172             63,  // Four AES blocks or two ChaCha20 blocks, minus 1.
173             64,  // Four AES blocks or two ChaCha20 blocks.
174             65,  // Four AES blocks or two ChaCha20 blocks, plus 1.
175             79,  // Five AES blocks, minus 1.
176             80,  // Five AES blocks.
177             81,  // Five AES blocks, plus 1.
178             95,  // Six AES blocks or three ChaCha20 blocks, minus 1.
179             96,  // Six AES blocks or three ChaCha20 blocks.
180             97,  // Six AES blocks or three ChaCha20 blocks, plus 1.
181             111, // Seven AES blocks, minus 1.
182             112, // Seven AES blocks.
183             113, // Seven AES blocks, plus 1.
184             127, // Eight AES blocks or four ChaCha20 blocks, minus 1.
185             128, // Eight AES blocks or four ChaCha20 blocks.
186             129, // Eight AES blocks or four ChaCha20 blocks, plus 1.
187             143, // Nine AES blocks, minus 1.
188             144, // Nine AES blocks.
189             145, // Nine AES blocks, plus 1.
190             255, // 16 AES blocks or 8 ChaCha20 blocks, minus 1.
191             256, // 16 AES blocks or 8 ChaCha20 blocks.
192             257, // 16 AES blocks or 8 ChaCha20 blocks, plus 1.
193         ];
194 
195         let mut more_comprehensive_in_prefix_lengths = [0; 4096];
196         let in_prefix_lengths;
197         if cfg!(debug_assertions) {
198             in_prefix_lengths = &MINIMAL_IN_PREFIX_LENS[..];
199         } else {
200             for b in 0..more_comprehensive_in_prefix_lengths.len() {
201                 more_comprehensive_in_prefix_lengths[b] = b;
202             }
203             in_prefix_lengths = &more_comprehensive_in_prefix_lengths[..];
204         }
205         let mut o_in_out = vec![123u8; 4096];
206 
207         for in_prefix_len in in_prefix_lengths.iter() {
208             o_in_out.truncate(0);
209             for _ in 0..*in_prefix_len {
210                 o_in_out.push(123);
211             }
212             o_in_out.extend_from_slice(&ct[..]);
213 
214             let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap();
215             let o_result = open(
216                 aead_alg,
217                 &key_bytes,
218                 nonce,
219                 aead::Aad::from(&aad[..]),
220                 &mut o_in_out,
221                 *in_prefix_len..,
222             );
223             match error {
224                 None => {
225                     assert!(s_result.is_ok());
226                     assert_eq!(&plaintext[..], o_result.unwrap());
227                 }
228                 Some(ref error) if error == "WRONG_NONCE_LENGTH" => {
229                     assert_eq!(Err(error::Unspecified), s_result);
230                     assert_eq!(Err(error::Unspecified), o_result);
231                 }
232                 Some(error) => {
233                     unreachable!("Unexpected error test case: {}", error);
234                 }
235             };
236         }
237 
238         Ok(())
239     });
240 }
241 
seal_with_key( algorithm: &'static aead::Algorithm, key: &[u8], nonce: aead::Nonce, aad: aead::Aad<&[u8]>, in_out: &mut Vec<u8>, ) -> Result<(), error::Unspecified>242 fn seal_with_key(
243     algorithm: &'static aead::Algorithm,
244     key: &[u8],
245     nonce: aead::Nonce,
246     aad: aead::Aad<&[u8]>,
247     in_out: &mut Vec<u8>,
248 ) -> Result<(), error::Unspecified> {
249     let mut s_key: aead::SealingKey<OneNonceSequence> = make_key(algorithm, key, nonce);
250     s_key.seal_in_place_append_tag(aad, in_out)
251 }
252 
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>253 fn open_with_key<'a>(
254     algorithm: &'static aead::Algorithm,
255     key: &[u8],
256     nonce: aead::Nonce,
257     aad: aead::Aad<&[u8]>,
258     in_out: &'a mut [u8],
259     ciphertext_and_tag: RangeFrom<usize>,
260 ) -> Result<&'a mut [u8], error::Unspecified> {
261     let mut o_key: aead::OpeningKey<OneNonceSequence> = make_key(algorithm, key, nonce);
262     o_key.open_within(aad, in_out, ciphertext_and_tag)
263 }
264 
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>265 fn seal_with_less_safe_key(
266     algorithm: &'static aead::Algorithm,
267     key: &[u8],
268     nonce: aead::Nonce,
269     aad: aead::Aad<&[u8]>,
270     in_out: &mut Vec<u8>,
271 ) -> Result<(), error::Unspecified> {
272     let key = make_less_safe_key(algorithm, key);
273     key.seal_in_place_append_tag(nonce, aad, in_out)
274 }
275 
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>276 fn open_with_less_safe_key<'a>(
277     algorithm: &'static aead::Algorithm,
278     key: &[u8],
279     nonce: aead::Nonce,
280     aad: aead::Aad<&[u8]>,
281     in_out: &'a mut [u8],
282     ciphertext_and_tag: RangeFrom<usize>,
283 ) -> Result<&'a mut [u8], error::Unspecified> {
284     let key = make_less_safe_key(algorithm, key);
285     key.open_within(nonce, aad, in_out, ciphertext_and_tag)
286 }
287 
test_aead_key_sizes(aead_alg: &'static aead::Algorithm)288 fn test_aead_key_sizes(aead_alg: &'static aead::Algorithm) {
289     let key_len = aead_alg.key_len();
290     let key_data = vec![0u8; key_len * 2];
291 
292     // Key is the right size.
293     assert!(aead::UnboundKey::new(aead_alg, &key_data[..key_len]).is_ok());
294 
295     // Key is one byte too small.
296     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len - 1)]).is_err());
297 
298     // Key is one byte too large.
299     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len + 1)]).is_err());
300 
301     // Key is half the required size.
302     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len / 2)]).is_err());
303 
304     // Key is twice the required size.
305     assert!(aead::UnboundKey::new(aead_alg, &key_data[..(key_len * 2)]).is_err());
306 
307     // Key is empty.
308     assert!(aead::UnboundKey::new(aead_alg, &[]).is_err());
309 
310     // Key is one byte.
311     assert!(aead::UnboundKey::new(aead_alg, &[0]).is_err());
312 }
313 
314 // Test that we reject non-standard nonce sizes.
315 #[test]
test_aead_nonce_sizes() -> Result<(), error::Unspecified>316 fn test_aead_nonce_sizes() -> Result<(), error::Unspecified> {
317     let nonce_len = aead::NONCE_LEN;
318     let nonce = vec![0u8; nonce_len * 2];
319 
320     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..nonce_len]).is_ok());
321     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len - 1)]).is_err());
322     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len + 1)]).is_err());
323     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len / 2)]).is_err());
324     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..(nonce_len * 2)]).is_err());
325     assert!(aead::Nonce::try_assume_unique_for_key(&[]).is_err());
326     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..1]).is_err());
327     assert!(aead::Nonce::try_assume_unique_for_key(&nonce[..16]).is_err()); // 128 bits.
328 
329     Ok(())
330 }
331 
332 #[test]
aead_chacha20_poly1305_openssh()333 fn aead_chacha20_poly1305_openssh() {
334     // TODO: test_aead_key_sizes(...);
335 
336     test::run(
337         test_file!("aead_chacha20_poly1305_openssh_tests.txt"),
338         |section, test_case| {
339             assert_eq!(section, "");
340 
341             // XXX: `polyfill::convert` isn't available here.
342             let key_bytes = {
343                 let as_vec = test_case.consume_bytes("KEY");
344                 let mut as_array = [0u8; aead::chacha20_poly1305_openssh::KEY_LEN];
345                 as_array.copy_from_slice(&as_vec);
346                 as_array
347             };
348 
349             let sequence_number = test_case.consume_usize("SEQUENCE_NUMBER");
350             assert_eq!(sequence_number as u32 as usize, sequence_number);
351             let sequence_num = sequence_number as u32;
352             let plaintext = test_case.consume_bytes("IN");
353             let ct = test_case.consume_bytes("CT");
354             let expected_tag = test_case.consume_bytes("TAG");
355 
356             // TODO: Add some tests for when things fail.
357             //let error = test_case.consume_optional_string("FAILS");
358 
359             let mut tag = [0u8; aead::chacha20_poly1305_openssh::TAG_LEN];
360             let mut s_in_out = plaintext.clone();
361             let s_key = aead::chacha20_poly1305_openssh::SealingKey::new(&key_bytes);
362             let () = s_key.seal_in_place(sequence_num, &mut s_in_out[..], &mut tag);
363             assert_eq!(&ct, &s_in_out);
364             assert_eq!(&expected_tag, &tag);
365             let o_key = aead::chacha20_poly1305_openssh::OpeningKey::new(&key_bytes);
366 
367             {
368                 let o_result = o_key.open_in_place(sequence_num, &mut s_in_out[..], &tag);
369                 assert_eq!(o_result, Ok(&plaintext[4..]));
370             }
371             assert_eq!(&s_in_out[..4], &ct[..4]);
372             assert_eq!(&s_in_out[4..], &plaintext[4..]);
373 
374             Ok(())
375         },
376     );
377 }
378 
379 #[test]
test_tag_traits()380 fn test_tag_traits() {
381     test::compile_time_assert_send::<aead::Tag>();
382     test::compile_time_assert_sync::<aead::Tag>();
383 }
384 
385 #[test]
test_aead_key_debug()386 fn test_aead_key_debug() {
387     let key_bytes = [0; 32];
388     let nonce = [0; aead::NONCE_LEN];
389 
390     let key = aead::UnboundKey::new(&aead::AES_256_GCM, &key_bytes).unwrap();
391     assert_eq!(
392         "UnboundKey { algorithm: AES_256_GCM }",
393         format!("{:?}", key)
394     );
395 
396     let sealing_key: aead::SealingKey<OneNonceSequence> = make_key(
397         &aead::CHACHA20_POLY1305,
398         &key_bytes,
399         aead::Nonce::try_assume_unique_for_key(&nonce).unwrap(),
400     );
401     assert_eq!(
402         "SealingKey { algorithm: CHACHA20_POLY1305 }",
403         format!("{:?}", sealing_key)
404     );
405 
406     let opening_key: aead::OpeningKey<OneNonceSequence> = make_key(
407         &aead::AES_256_GCM,
408         &key_bytes,
409         aead::Nonce::try_assume_unique_for_key(&nonce).unwrap(),
410     );
411     assert_eq!(
412         "OpeningKey { algorithm: AES_256_GCM }",
413         format!("{:?}", opening_key)
414     );
415 
416     let key: aead::LessSafeKey = make_less_safe_key(&aead::CHACHA20_POLY1305, &key_bytes);
417     assert_eq!(
418         "LessSafeKey { algorithm: CHACHA20_POLY1305 }",
419         format!("{:?}", key)
420     );
421 }
422 
make_key<K: aead::BoundKey<OneNonceSequence>>( algorithm: &'static aead::Algorithm, key: &[u8], nonce: aead::Nonce, ) -> K423 fn make_key<K: aead::BoundKey<OneNonceSequence>>(
424     algorithm: &'static aead::Algorithm,
425     key: &[u8],
426     nonce: aead::Nonce,
427 ) -> K {
428     let key = aead::UnboundKey::new(algorithm, key).unwrap();
429     let nonce_sequence = OneNonceSequence::new(nonce);
430     K::new(key, nonce_sequence)
431 }
432 
make_less_safe_key(algorithm: &'static aead::Algorithm, key: &[u8]) -> aead::LessSafeKey433 fn make_less_safe_key(algorithm: &'static aead::Algorithm, key: &[u8]) -> aead::LessSafeKey {
434     let key = aead::UnboundKey::new(algorithm, key).unwrap();
435     aead::LessSafeKey::new(key)
436 }
437 
438 struct OneNonceSequence(Option<aead::Nonce>);
439 
440 impl OneNonceSequence {
441     /// Constructs the sequence allowing `advance()` to be called
442     /// `allowed_invocations` times.
new(nonce: aead::Nonce) -> Self443     fn new(nonce: aead::Nonce) -> Self {
444         Self(Some(nonce))
445     }
446 }
447 
448 impl aead::NonceSequence for OneNonceSequence {
advance(&mut self) -> Result<aead::Nonce, error::Unspecified>449     fn advance(&mut self) -> Result<aead::Nonce, error::Unspecified> {
450         self.0.take().ok_or(error::Unspecified)
451     }
452 }
453