// Copyright 2015 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. use ring::{digest, error, hkdf, test, test_file}; #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] wasm_bindgen_test_configure!(run_in_browser); #[test] fn hkdf_tests() { test::run(test_file!("hkdf_tests.txt"), |section, test_case| { assert_eq!(section, ""); let alg = { let digest_alg = test_case .consume_digest_alg("Hash") .ok_or(error::Unspecified)?; if digest_alg == &digest::SHA256 { hkdf::HKDF_SHA256 } else { // TODO: add test vectors for other algorithms panic!("unsupported algorithm: {:?}", digest_alg); } }; let secret = test_case.consume_bytes("IKM"); let salt = test_case.consume_bytes("salt"); let info = test_case.consume_bytes("info"); let _ = test_case.consume_bytes("PRK"); let expected_out = test_case.consume_bytes("OKM"); let salt = hkdf::Salt::new(alg, &salt); // TODO: test multi-part info, especially with empty parts. let My(out) = salt .extract(&secret) .expand(&[&info], My(expected_out.len())) .unwrap() .into(); assert_eq!(out, expected_out); Ok(()) }); } #[test] fn hkdf_output_len_tests() { for &alg in &[hkdf::HKDF_SHA256, hkdf::HKDF_SHA384, hkdf::HKDF_SHA512] { const MAX_BLOCKS: usize = 255; let salt = hkdf::Salt::new(alg, &[]); let prk = salt.extract(&[]); // TODO: enforce minimum length. { // Test zero length. let okm = prk.expand(&[b"info"], My(0)).unwrap(); let result: My> = okm.into(); assert_eq!(&result.0, &[]); } let max_out_len = MAX_BLOCKS * alg.hmac_algorithm().digest_algorithm().output_len; { // Test maximum length output succeeds. let okm = prk.expand(&[b"info"], My(max_out_len)).unwrap(); let result: My> = okm.into(); assert_eq!(result.0.len(), max_out_len); } { // Test too-large output fails. assert!(prk.expand(&[b"info"], My(max_out_len + 1)).is_err()); } { // Test length mismatch (smaller). let okm = prk.expand(&[b"info"], My(2)).unwrap(); let mut buf = [0u8; 1]; assert_eq!(okm.fill(&mut buf), Err(error::Unspecified)); } { // Test length mismatch (larger). let okm = prk.expand(&[b"info"], My(2)).unwrap(); let mut buf = [0u8; 3]; assert_eq!(okm.fill(&mut buf), Err(error::Unspecified)); } { // Control for above two tests. let okm = prk.expand(&[b"info"], My(2)).unwrap(); let mut buf = [0u8; 2]; assert_eq!(okm.fill(&mut buf), Ok(())); } } } /// Generic newtype wrapper that lets us implement traits for externally-defined /// types. #[derive(Debug, PartialEq)] struct My(T); impl hkdf::KeyType for My { fn len(&self) -> usize { self.0 } } impl From>> for My> { fn from(okm: hkdf::Okm>) -> Self { let mut r = vec![0u8; okm.len().0]; okm.fill(&mut r).unwrap(); Self(r) } }