Skip to content

Commit

Permalink
replace test vectors with wycheproof-rs (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
tofay authored Nov 21, 2024
1 parent 9f75f2e commit b82e85a
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 7,482 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ rstest = "0.23.0"
# Use aws_lc_rs to test our provider
rustls = { version = "0.23.0", features = ["aws_lc_rs"] }
rustls-pemfile = "2"
serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0.133"
webpki-roots = "0.26"
wycheproof = { version = "0.6.0", default-features = false, features = [
"aead",
"hkdf",
] }
134 changes: 53 additions & 81 deletions src/aead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,127 +88,99 @@ impl Algorithm {

#[cfg(test)]
mod test {
use wycheproof::{aead::TestFlag, TestResult};

use crate::test::schemas::aead;
use std::{fs, path::PathBuf};
fn test_aead(alg: super::Algorithm) {
let test_name = match alg {
super::Algorithm::Aes128Gcm | super::Algorithm::Aes256Gcm => {
wycheproof::aead::TestName::AesGcm
}
#[cfg(all(chacha, not(feature = "fips")))]
super::Algorithm::ChaCha20Poly1305 => wycheproof::aead::TestName::ChaCha20Poly1305,
};
let test_set = wycheproof::aead::TestSet::load(test_name).unwrap();

fn test_aes(alg: super::Algorithm) {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("test")
.join("vectors")
.join("aes_gcm_test.json");
let tests: aead::AeadTestFile =
serde_json::from_str(&fs::read_to_string(path).unwrap()).unwrap();
let mut counter = 0;

for group in tests
for group in test_set
.test_groups
.unwrap()
.iter()
.filter(|group| group.key_size.unwrap() == 8 * i64::try_from(alg.key_size()).unwrap())
.filter(|group| group.iv_size.unwrap() == 96)
.into_iter()
.filter(|group| group.key_size == 8 * alg.key_size())
.filter(|group| group.nonce_size == 96)
{
for test in group.tests.as_ref().unwrap() {
dbg!(test.tc_id);
let key = test
.key
.as_deref()
.map(|key| hex::decode(key).unwrap())
.unwrap();
let iv = test
.iv
.as_deref()
.map(|iv| hex::decode(iv).unwrap())
.unwrap();
let aad = test
.aad
.as_deref()
.map(|aad| hex::decode(aad).unwrap())
.unwrap();
let msg = test
.msg
.as_deref()
.map(|msg| hex::decode(msg).unwrap())
.unwrap();
let ciphertext = test
.ct
.as_deref()
.map(|ct| hex::decode(ct).unwrap())
.unwrap();
let tag = test
.tag
.as_deref()
.map(|tag| hex::decode(tag).unwrap())
.unwrap();

for test in group.tests {
counter += 1;
let mut iv_bytes = [0u8; 12];
iv_bytes.copy_from_slice(&iv[0..12]);
iv_bytes.copy_from_slice(&test.nonce[0..12]);

let mut actual_ciphertext = msg.clone();
let mut actual_ciphertext = test.pt.to_vec();
let actual_tag = alg
.encrypt_in_place(&key, &iv_bytes, &aad, &mut actual_ciphertext)
.encrypt_in_place(&test.key, &iv_bytes, &test.aad, &mut actual_ciphertext)
.unwrap();

match test.result.as_ref().unwrap() {
aead::Result::Invalid => {
if test
.flags
.as_ref()
.unwrap()
.iter()
.any(|flag| flag == "ModifiedTag")
{
match &test.result {
TestResult::Invalid => {
if test.flags.iter().any(|flag| *flag == TestFlag::ModifiedTag) {
assert_ne!(
actual_tag[..],
tag[..],
test.tag[..],
"Expected incorrect tag. Id {}: {}",
test.tc_id.unwrap(),
test.comment.as_deref().unwrap()
test.tc_id,
test.comment
);
}
}
aead::Result::Valid | aead::Result::Acceptable => {
TestResult::Valid | TestResult::Acceptable => {
assert_eq!(
actual_ciphertext,
ciphertext,
actual_ciphertext[..],
test.ct[..],
"Test case failed {}: {}",
test.tc_id.unwrap(),
test.comment.as_deref().unwrap()
test.tc_id,
test.comment
);
assert_eq!(
actual_tag[..],
tag[..],
test.tag[..],
"Test case failed {}: {}",
test.tc_id.unwrap(),
test.comment.as_deref().unwrap()
test.tc_id,
test.comment
);
}
}

let mut data = ciphertext.to_vec();
data.extend_from_slice(&tag);
let res = alg.decrypt_in_place(&key, &iv_bytes, &aad, &mut data);
let mut data = test.ct.to_vec();
data.extend_from_slice(&test.tag);
let res = alg.decrypt_in_place(&test.key, &iv_bytes, &test.aad, &mut data);

match test.result.as_ref().unwrap() {
aead::Result::Invalid => {
match &test.result {
TestResult::Invalid => {
assert!(res.is_err());
}
aead::Result::Valid | aead::Result::Acceptable => {
assert_eq!(res, Ok(msg.len()));
assert_eq!(&data[..res.unwrap()], &msg[..]);
TestResult::Valid | TestResult::Acceptable => {
assert_eq!(res, Ok(test.pt.len()));
assert_eq!(&data[..res.unwrap()], &test.pt[..]);
}
}
}
}

// Ensure we ran some tests.
assert!(counter > 50);
}

#[test]
fn test_aes_128() {
test_aes(super::Algorithm::Aes128Gcm);
test_aead(super::Algorithm::Aes128Gcm);
}

#[test]
fn test_aes_256() {
test_aes(super::Algorithm::Aes256Gcm);
test_aead(super::Algorithm::Aes256Gcm);
}

#[cfg(all(chacha, not(feature = "fips")))]
#[test]
fn test_chacha() {
test_aead(super::Algorithm::ChaCha20Poly1305);
}
}
56 changes: 16 additions & 40 deletions src/hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,41 +126,29 @@ fn add_hkdf_info<T>(ctx: &mut PkeyCtxRef<T>, info: &[&[u8]]) -> Result<(), Error

#[cfg(test)]
mod test {
use crate::test::schemas::hkdf::{self, HkdfTestFile};
use rustls::crypto::tls13::Hkdf;
use std::{fs, path::PathBuf};

fn test_hkdf(hkdf: &dyn Hkdf, test_file: HkdfTestFile) {
for test_group in test_file.test_groups.unwrap() {
for test in test_group.tests.unwrap() {
let salt = test.salt.as_deref().map(|salt| hex::decode(salt).unwrap());
let ikm = test
.ikm
.as_deref()
.map(|ikm| hex::decode(ikm).unwrap())
.unwrap();
let expected_okm = test
.okm
.as_deref()
.map(|okm| hex::decode(okm).unwrap())
.unwrap();
let info = test.info.as_deref().map(|info| hex::decode(info).unwrap());
use wycheproof::{hkdf::TestName, TestResult};

fn test_hkdf(hkdf: &dyn Hkdf, test_name: TestName) {
let test_set = wycheproof::hkdf::TestSet::load(test_name).unwrap();

for test_group in test_set.test_groups {
for test in test_group.tests {
dbg!(&test);

let prk_expander = hkdf.extract_from_secret(salt.as_deref(), &ikm);
let prk_expander = hkdf.extract_from_secret(Some(&test.salt), &test.ikm);

let mut okm = vec![0; test.size.unwrap().try_into().unwrap()];
let res = prk_expander.expand_slice(&[info.as_deref().unwrap_or(&[])], &mut okm);
let mut okm = vec![0; test.size];
let res = prk_expander.expand_slice(&[&test.info], &mut okm);

match &test.result.unwrap() {
hkdf::Result::Acceptable | hkdf::Result::Valid => {
match &test.result {
TestResult::Acceptable | TestResult::Valid => {
assert!(res.is_ok());
assert_eq!(okm, expected_okm, "Failed test: {}", test.comment.unwrap());
assert_eq!(okm[..], test.okm[..], "Failed test: {}", test.comment);
}
hkdf::Result::Invalid => {
TestResult::Invalid => {
dbg!(&res);
assert!(res.is_err(), "Failed test: {}", test.comment.unwrap())
assert!(res.is_err(), "Failed test: {}", test.comment)
}
}
}
Expand All @@ -171,25 +159,13 @@ mod test {
fn hkdf_sha256() {
let suite = crate::cipher_suite::TLS13_AES_128_GCM_SHA256;
let hkdf = suite.tls13().unwrap().hkdf_provider;
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("test")
.join("vectors")
.join("hkdf_sha256_test.json");
let tests: HkdfTestFile = serde_json::from_str(&fs::read_to_string(path).unwrap()).unwrap();
test_hkdf(hkdf, tests);
test_hkdf(hkdf, TestName::HkdfSha256);
}

#[test]
fn hkdf_sha384() {
let suite = crate::cipher_suite::TLS13_AES_256_GCM_SHA384;
let hkdf = suite.tls13().unwrap().hkdf_provider;
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("test")
.join("vectors")
.join("hkdf_sha384_test.json");
let tests: HkdfTestFile = serde_json::from_str(&fs::read_to_string(path).unwrap()).unwrap();
test_hkdf(hkdf, tests);
test_hkdf(hkdf, TestName::HkdfSha384);
}
}
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ mod kx;
mod prf;
mod quic;
mod signer;
#[cfg(test)]
mod test;
#[cfg(feature = "tls12")]
mod tls12;
mod tls13;
Expand Down
2 changes: 0 additions & 2 deletions src/test/mod.rs

This file was deleted.

79 changes: 0 additions & 79 deletions src/test/schemas/aead.rs

This file was deleted.

Loading

0 comments on commit b82e85a

Please sign in to comment.