Skip to content

Commit

Permalink
Add new Wycheproof test vectors for (X)ChaCha20Poly1305, HMAC-SHA512 …
Browse files Browse the repository at this point in the history
…and HKDF-HMAC-SHA512 (#116)

* tests: Add updated wycheproof test vectors for ChaCha20Poly1305 and new ones for XChaCha20Poly1305

* tests: Add new Wycheproof test vectors for HMAC-SHA512

* tests: Add new Wycheproof test vectors for HKDF-HMAC-SHA512

* tests: Refactor HKDF test runner

* tests: Refactor HMAC test runner

* fmt

* tests: Refactor Wycheproof tests runners
  • Loading branch information
brycx authored Jan 28, 2020
1 parent b1771b9 commit 4b552bc
Show file tree
Hide file tree
Showing 16 changed files with 10,262 additions and 2,026 deletions.
2 changes: 1 addition & 1 deletion src/hazardous/kdf/hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub fn verify(
info: Option<&[u8]>,
dst_out: &mut [u8],
) -> Result<(), UnknownCryptoError> {
expand(&extract(salt, ikm)?, info, dst_out)?;
derive_key(salt, ikm, info, dst_out)?;
util::secure_cmp(&dst_out, expected)
}

Expand Down
82 changes: 42 additions & 40 deletions tests/aead/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub mod boringssl_xchacha20_poly1305;
pub mod other_xchacha20_poly1305;
pub mod pynacl_streaming_aead;
pub mod rfc_chacha20_poly1305;
pub mod wycheproof_chacha20_poly1305;
pub mod wycheproof_aead;

extern crate orion;
use self::{
Expand Down Expand Up @@ -102,6 +102,7 @@ fn wycheproof_test_runner(
output: &[u8],
result: bool,
tcid: u64,
is_ietf: bool,
) -> Result<(), UnknownCryptoError> {
// Leave test vectors out that have empty input/output and are otherwise valid
// since orion does not accept this. This will be test cases with "tcId" = 2, 3.
Expand All @@ -115,56 +116,57 @@ fn wycheproof_test_runner(
let mut dst_pt_out = vec![0u8; input.len()];

if result {
aead::chacha20poly1305::seal(
&SecretKey::from_slice(&key)?,
&chacha20poly1305::Nonce::from_slice(&nonce)?,
input,
Some(aad),
&mut dst_ct_out,
)?;

aead::chacha20poly1305::open(
&SecretKey::from_slice(&key)?,
&chacha20poly1305::Nonce::from_slice(&nonce)?,
&dst_ct_out,
Some(aad),
&mut dst_pt_out,
)?;
let key = SecretKey::from_slice(&key)?;

if is_ietf {
let nonce = chacha20poly1305::Nonce::from_slice(&nonce)?;
chacha20poly1305::seal(&key, &nonce, input, Some(aad), &mut dst_ct_out)?;
chacha20poly1305::open(&key, &nonce, &dst_ct_out, Some(aad), &mut dst_pt_out)?;
} else {
let nonce = xchacha20poly1305::Nonce::from_slice(&nonce)?;
xchacha20poly1305::seal(&key, &nonce, input, Some(aad), &mut dst_ct_out)?;
xchacha20poly1305::open(&key, &nonce, &dst_ct_out, Some(aad), &mut dst_pt_out)?;
}

assert!(dst_ct_out[..input.len()].as_ref() == output);
assert!(dst_ct_out[input.len()..].as_ref() == tag);
assert!(dst_pt_out[..].as_ref() == input);
} else {
let new_key = SecretKey::from_slice(&key);
let new_nonce = chacha20poly1305::Nonce::from_slice(&nonce);

// Detecting cases where there is invalid size of nonce and/or key
if new_key.is_err() || new_nonce.is_err() {
return Ok(());
// Tests that run here have a "invalid" flag set
let key = match SecretKey::from_slice(&key) {
Ok(k) => k,
Err(UnknownCryptoError) => return Ok(()), // Invalid key size test
};

// Save the return values from sealing/opening operations
// to match for errors.
let sealres: Result<(), UnknownCryptoError>;
let openres: Result<(), UnknownCryptoError>;

if is_ietf {
let nonce = match chacha20poly1305::Nonce::from_slice(&nonce) {
Ok(n) => n,
Err(UnknownCryptoError) => return Ok(()), // Invalid nonce size test
};

sealres = chacha20poly1305::seal(&key, &nonce, input, Some(aad), &mut dst_ct_out);
openres = chacha20poly1305::open(&key, &nonce, &dst_ct_out, Some(aad), &mut dst_pt_out);
} else {
let nonce = match xchacha20poly1305::Nonce::from_slice(&nonce) {
Ok(n) => n,
Err(UnknownCryptoError) => return Ok(()), // Invalid nonce size test
};

sealres = xchacha20poly1305::seal(&key, &nonce, input, Some(aad), &mut dst_ct_out);
openres =
xchacha20poly1305::open(&key, &nonce, &dst_ct_out, Some(aad), &mut dst_pt_out);
}

let encryption = aead::chacha20poly1305::seal(
&new_key.unwrap(),
&new_nonce.unwrap(),
input,
Some(aad),
&mut dst_ct_out,
);
// Because of the early return, there is no need to check for invalid size of
// nonce and/or key
let decryption = aead::chacha20poly1305::open(
&SecretKey::from_slice(&key)?,
&chacha20poly1305::Nonce::from_slice(&nonce)?,
&dst_ct_out,
Some(aad),
&mut dst_pt_out,
);

// Test case results may be invalid, but this does not mean both seal() and
// open() fails. We use a match arm to allow failure combinations, with
// possible successful calls, but never a combination of two successful
// calls where the output matches the expected values.
match (encryption, decryption) {
match (sealres, openres) {
(Ok(_), Err(_)) => (),
(Err(_), Ok(_)) => (),
(Err(_), Err(_)) => (),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
// Testing against Google Wycheproof test vectors
// Latest commit when these test vectors were pulled: https://github.com/google/wycheproof/commit/8f2cba4d3fe693aa312fed6939ef5454952d830d
// Latest commit when these test vectors were pulled: https://github.com/google/wycheproof/commit/2196000605e45d91097147c9c71f26b72af58003
extern crate hex;
extern crate serde_json;

use self::hex::decode;

use self::serde_json::{Deserializer, Value};
use crate::aead::wycheproof_test_runner as chacha20_poly1305_test_runner;
use crate::aead::wycheproof_test_runner;
use std::{fs::File, io::BufReader};

#[test]
fn test_wycheproof() {
let file = File::open("./tests/test_data/original/Wycheproof_ChaCha20_Poly1305.json").unwrap();
fn wycheproof_runner(path: &str, is_ietf: bool) {
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
let stream = Deserializer::from_reader(reader).into_iter::<Value>();

Expand Down Expand Up @@ -40,9 +39,10 @@ fn test_wycheproof() {
_ => panic!("Unrecognized result detected!"),
};
let tcid = test_case.get("tcId").unwrap().as_u64().unwrap();
println!("tcId: {}, is_ietf: {}", tcid, is_ietf);

chacha20_poly1305_test_runner(
&key, &iv, &aad, &tag, &msg, &ct, result, tcid,
wycheproof_test_runner(
&key, &iv, &aad, &tag, &msg, &ct, result, tcid, is_ietf,
)
.unwrap();
}
Expand All @@ -52,3 +52,15 @@ fn test_wycheproof() {
}
}
}

#[test]
fn test_wycheproof_aead() {
wycheproof_runner(
"./tests/test_data/original/wycheproof_chacha20_poly1305_test.json",
true,
);
wycheproof_runner(
"./tests/test_data/original/wycheproof_xchacha20_poly1305_test.json",
false,
);
}
55 changes: 25 additions & 30 deletions tests/kdf/custom_hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@ mod custom_hkdf {
let ikm = decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
let salt = decode("000102030405060708090a0b0c").unwrap();
let info = decode("").unwrap();
let mut okm = [0u8; 32];

let expected_okm =
decode("f81b87481a18b664936daeb222f58cba0ebc55f5c85996b9f1cb396c327b70bb").unwrap();

assert!(hkdf_test_runner(
hkdf_test_runner(
None,
&expected_okm,
&salt,
&ikm,
&info,
&mut okm
));
expected_okm.len(),
true,
);
}

#[test]
Expand All @@ -40,8 +39,6 @@ mod custom_hkdf {
.unwrap();
let salt = "salt".as_bytes();
let info = "random InF\0".as_bytes();
let mut okm = [0u8; 128];

let expected_okm = decode(
"a246ef99f6a0f783fc004682508e6f288f036469788f004fcbac9414caa889fa175e746ee663914d\
678c155d510fa536f7d49b1054e85e7751d9745ea02079a78608eec9aacdd82fa9421d6223c158c71\
Expand All @@ -50,14 +47,15 @@ mod custom_hkdf {
)
.unwrap();

assert!(hkdf_test_runner(
hkdf_test_runner(
None,
&expected_okm,
&salt,
&ikm,
&info,
&mut okm
));
expected_okm.len(),
true,
);
}

#[test]
Expand All @@ -70,8 +68,6 @@ mod custom_hkdf {
)
.unwrap();
let info = decode("").unwrap();
let mut okm = [0u8; 256];

let expected_okm = decode(
"245d63179146a61ca1a25f92c38391d406bb52da4b773714fb0e43ce90\
84ce430f43e1980a8817cf0af320fb684776d81f674d2b187449d62200d3e39cb51ab7a444f7964944895\
Expand All @@ -83,23 +79,22 @@ mod custom_hkdf {
)
.unwrap();

assert!(hkdf_test_runner(
hkdf_test_runner(
None,
&expected_okm,
&salt,
&ikm,
&info,
&mut okm
));
expected_okm.len(),
true,
);
}

#[test]
fn test_case_4() {
let ikm = decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
let salt = "s$#$#%$#SBGHWE@#W#lt".as_bytes();
let info = "random InF\0".as_bytes();
let mut okm = [0u8; 256];

let expected_okm = decode(
"e93182a8af74a1e70a6202075759bbbceb1926a18aa9f9ee31796557\
0b507cea7ef11f94d83760bb6f8a2f6031edb581c1ae43f45ead820223d34c6ffadab43d3cfaf9cd782\
Expand All @@ -110,34 +105,35 @@ mod custom_hkdf {
7e9fbf127ff88d33b984582ced74fa029b50f441e",
)
.unwrap();
assert!(hkdf_test_runner(

hkdf_test_runner(
None,
&expected_okm,
&salt,
&ikm,
&info,
&mut okm
));
expected_okm.len(),
true,
);
}

#[test]
fn test_case_5() {
let ikm = "passwordPASSWORDpassword".as_bytes();
let salt = "salt".as_bytes();
let info = decode("").unwrap();
let mut okm = [0u8; 32];

let expected_okm =
decode("1ef9dccc02d5786f0d7133da824afe212547f2d8c97e9299345db86814dcb9b8").unwrap();

assert!(hkdf_test_runner(
hkdf_test_runner(
None,
&expected_okm,
&salt,
&ikm,
&info,
&mut okm
));
expected_okm.len(),
true,
);
}

#[test]
Expand All @@ -150,17 +146,16 @@ mod custom_hkdf {
3f4f5f6f7f8f9fafbfcfdfeff",
)
.unwrap();
let mut okm = [0u8; 16];

let expected_okm = decode("8ae15623215eaaa156bad552f411c4ad").unwrap();

assert!(hkdf_test_runner(
hkdf_test_runner(
None,
&expected_okm,
&salt,
&ikm,
&info,
&mut okm
));
expected_okm.len(),
true,
);
}
}
22 changes: 15 additions & 7 deletions tests/kdf/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
pub mod custom_hkdf;
pub mod custom_pbkdf2;
pub mod other_hkdf;
pub mod wycheproof_hkdf;

extern crate orion;
use self::orion::hazardous::{kdf::hkdf::*, mac::hmac};

pub fn hkdf_test_runner(
excp_prk: Option<&[u8]>,
excp_okm: &[u8],
expected_prk: Option<&[u8]>,
expected_okm: &[u8],
salt: &[u8],
ikm: &[u8],
info: &[u8],
okm_out: &mut [u8],
) -> bool {
if excp_prk.is_some() {
okm_len: usize,
valid_result: bool,
) {
if expected_prk.is_some() {
let actual_prk = extract(salt, &ikm).unwrap();
assert!(actual_prk == hmac::Tag::from_slice(excp_prk.unwrap()).unwrap());
assert!(actual_prk == hmac::Tag::from_slice(expected_prk.unwrap()).unwrap());
}

let mut okm_out = vec![0u8; okm_len];

// verify() also runs derive_key()
verify(excp_okm, salt, ikm, Some(&info), &mut okm_out.to_vec()).is_ok()
if valid_result {
assert!(verify(expected_okm, salt, ikm, Some(&info), &mut okm_out).is_ok());
} else {
assert!(verify(expected_okm, salt, ikm, Some(&info), &mut okm_out).is_err());
}
}
Loading

0 comments on commit 4b552bc

Please sign in to comment.