Skip to content

replace test vectors with wycheproof-rs #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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