aead_tests.rs 15 KB

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