use std::io;
use std::io::BufRead;
use crate::tests::*;
use serial_test::parallel;
#[derive(Debug)]
struct TestUnit {
line: usize,
count: usize,
mech: CK_MECHANISM_TYPE,
enc: bool,
key: Vec<u8>,
msg: Vec<u8>,
wp: Vec<u8>,
}
fn parse_buffer(s: &String, ln: usize, p: &str, len: isize) -> Option<Vec<u8>> {
let prefix = p.len() + 3;
if !s.starts_with(p) || !(&s[(prefix - 3)..prefix]).starts_with(" = ") {
return None;
}
let v = parse_or_panic!(hex::decode(&s[prefix..]); s; ln);
if len != -1 && v.len() != len as usize {
panic!(
"Length of {} ({}) does not match specified length: {} (line {})",
p,
v.len(),
len,
ln
);
}
Some(v)
}
fn parse_kw_vector(file: std::fs::File) -> Vec<TestUnit> {
let mut mech = CK_UNAVAILABLE_INFORMATION;
let mut enc = 0;
let mut keylen: isize = 1;
let mut plen: isize = 0;
let mut data = Vec::<TestUnit>::new();
for (l, line) in io::BufReader::new(file).lines().flatten().enumerate() {
let ln = l + 1;
if line.starts_with("#") {
if line.contains("KW-AE") {
mech = CKM_AES_KEY_WRAP;
enc = 1;
} else if line.contains("KW-AD") {
mech = CKM_AES_KEY_WRAP;
enc = 2;
} else if line.contains("KWP-AE") {
mech = CKM_AES_KEY_WRAP_KWP;
enc = 1;
} else if line.contains("KWP-AD") {
mech = CKM_AES_KEY_WRAP_KWP;
enc = 2;
}
if line.contains("AES-128") {
keylen = 16;
} else if line.contains("AES-192") {
keylen = 24;
} else if line.contains("AES-256") {
keylen = 32;
}
continue;
}
if line.len() == 0 {
continue;
}
if line.starts_with("[PLAINTEXT LENGTH = ") {
plen = (&line[20..(line.len() - 1)]).parse::<isize>().unwrap() / 8;
continue;
}
if line.starts_with("COUNT = ") {
let unit = TestUnit {
line: ln,
count: (&line[8..]).parse().unwrap(),
mech: mech,
enc: match enc {
1 => true,
2 => false,
_ => panic!("Undetermined E vs D operation"),
},
key: Vec::new(),
msg: Vec::new(),
wp: Vec::new(),
};
data.push(unit);
continue;
}
let unit = match data.last_mut() {
Some(u) => u,
None => panic!("No unit defined (line {})", ln),
};
if let Some(v) = parse_buffer(&line, ln, "C", -1) {
unit.wp = v;
continue;
}
if let Some(v) = parse_buffer(&line, ln, "K", keylen) {
unit.key = v;
continue;
}
if let Some(v) = parse_buffer(&line, ln, "P", plen) {
unit.msg = v;
continue;
}
if line.starts_with("FAIL") {
unit.msg.clear();
}
}
data
}
fn test_units(session: CK_SESSION_HANDLE, test_data: Vec<TestUnit>) {
for unit in test_data {
println!("Executing test at line {}", unit.line);
let key_handle = ret_or_panic!(import_object(
session,
CKO_SECRET_KEY,
&[(CKA_KEY_TYPE, CKK_AES)],
&[(CKA_VALUE, unit.key.as_slice())],
&[(CKA_ENCRYPT, true), (CKA_DECRYPT, true)],
));
if unit.enc {
let enc = ret_or_panic!(encrypt(
session,
key_handle,
unit.msg.as_slice(),
&CK_MECHANISM {
mechanism: unit.mech,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
}
));
if enc != unit.wp {
panic!(
"Failed unit test {} at line {} - values differ [{} != {}]",
unit.count,
unit.line,
hex::encode(enc),
hex::encode(unit.wp)
);
}
} else {
let ret = decrypt(
session,
key_handle,
unit.wp.as_slice(),
&CK_MECHANISM {
mechanism: unit.mech,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
},
);
match ret {
Err(e) => {
if unit.msg.len() == 0 {
continue;
}
panic!("Error {} in unit test at line {}", e, unit.line);
}
Ok(dec) => {
if dec != unit.msg {
panic!(
"Failed unit test at line {} - values differ [{} != {}]",
unit.line,
hex::encode(dec),
hex::encode(unit.msg)
);
}
}
}
}
}
}
fn test_kw_vector(mech: &str, op: &str, size: &str) {
let name = format!("{}_{}_{}", mech, op, size);
let filename = format!("testdata/kwtestvectors/{}.txt", name);
let file = match open_test_vector_file(&filename) {
Ok(Some(f)) => f,
Ok(None) => {
eprintln!(
"Warning: Test vector file '{}' not found, skipping test.",
filename
);
return;
}
Err(e) => {
panic!("Failed to open test vector file '{}': {}", filename, e)
}
};
let test_data = parse_kw_vector(file);
let db_name = format!("test_{}_vector", name);
let mut testtokn = TestToken::initialized(&db_name, None);
let session = testtokn.get_session(false);
testtokn.login();
test_units(session, test_data);
testtokn.finalize();
}
#[test]
#[parallel]
fn test_kw_ae_128_vector() {
test_kw_vector("KW", "AE", "128")
}
#[test]
#[parallel]
fn test_kw_ae_192_vector() {
test_kw_vector("KW", "AE", "192")
}
#[test]
#[parallel]
fn test_kw_ae_256_vector() {
test_kw_vector("KW", "AE", "256")
}
#[test]
#[parallel]
fn test_kw_ad_128_vector() {
test_kw_vector("KW", "AD", "128")
}
#[test]
#[parallel]
fn test_kw_ad_192_vector() {
test_kw_vector("KW", "AD", "192")
}
#[test]
#[parallel]
fn test_kw_ad_256_vector() {
test_kw_vector("KW", "AD", "256")
}
#[test]
#[parallel]
fn test_kwp_ae_128_vector() {
test_kw_vector("KWP", "AE", "128")
}
#[test]
#[parallel]
fn test_kwp_ae_192_vector() {
test_kw_vector("KWP", "AE", "192")
}
#[test]
#[parallel]
fn test_kwp_ae_256_vector() {
test_kw_vector("KWP", "AE", "256")
}
#[test]
#[parallel]
fn test_kwp_ad_128_vector() {
test_kw_vector("KWP", "AD", "128")
}
#[test]
#[parallel]
fn test_kwp_ad_192_vector() {
test_kw_vector("KWP", "AD", "192")
}
#[test]
#[parallel]
fn test_kwp_ad_256_vector() {
test_kw_vector("KWP", "AD", "256")
}