Skip to content

Migrate to const blobby parsing #1916

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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ signature = { path = "signature" }
der = { git = "https://github.com/RustCrypto/formats.git" }
pkcs8 = { git = "https://github.com/RustCrypto/formats.git" }
sec1 = { git = "https://github.com/RustCrypto/formats.git" }
blobby = { git = "https://github.com/RustCrypto/utils", branch = "blobby/const_prsing" }
137 changes: 93 additions & 44 deletions aead/src/dev.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,80 @@
//! Development-related functionality
use crate::{
Aead, AeadInOut, Nonce, Payload, Tag, TagPosition, array::typenum::Unsigned, inout::InOutBuf,
Aead, AeadInOut, Payload, Tag, TagPosition, array::typenum::Unsigned, inout::InOutBuf,
};
pub use blobby;
use crypto_common::KeyInit;

/// AEAD test vector
#[derive(Debug, Clone, Copy)]
pub struct TestVector {
/// Initialization key
pub key: &'static [u8],
/// Nonce
pub nonce: &'static [u8],
/// Additional associated data
pub aad: &'static [u8],
/// Plaintext
pub plaintext: &'static [u8],
/// Ciphertext
pub ciphertext: &'static [u8],
/// Whether the test vector should pass (`[1]`) or fail (`[0]`)
pub pass: &'static [u8],
}

/// Run AEAD test for the provided passing test vector
pub fn run_pass_test<C: AeadInOut>(
cipher: &C,
nonce: &Nonce<C>,
aad: &[u8],
pt: &[u8],
ct: &[u8],
pub fn pass_test<C: AeadInOut + KeyInit>(
&TestVector {
key,
nonce,
aad,
plaintext,
ciphertext,
pass,
}: &TestVector,
) -> Result<(), &'static str> {
assert_eq!(pass, &[1]);
let nonce = nonce.try_into().expect("wrong nonce size");
let cipher = <C as KeyInit>::new_from_slice(key).expect("failed to initialize the cipher");

let res = cipher
.encrypt(nonce, Payload { aad, msg: pt })
.encrypt(
nonce,
Payload {
aad,
msg: plaintext,
},
)
.map_err(|_| "encryption failure")?;
if res != ct {
if res != ciphertext {
return Err("encrypted data is different from target ciphertext");
}

let res = cipher
.decrypt(nonce, Payload { aad, msg: ct })
.decrypt(
nonce,
Payload {
aad,
msg: ciphertext,
},
)
.map_err(|_| "decryption failure")?;
if res != pt {
if res != plaintext {
return Err("decrypted data is different from target plaintext");
}

let (ct, tag) = match C::TAG_POSITION {
TagPosition::Prefix => {
let (tag, ct) = ct.split_at(C::TagSize::USIZE);
let (tag, ct) = ciphertext.split_at(C::TagSize::USIZE);
(ct, tag)
}
TagPosition::Postfix => ct.split_at(pt.len()),
TagPosition::Postfix => ciphertext.split_at(plaintext.len()),
};
let tag: &Tag<C> = tag.try_into().expect("tag has correct length");

// Fill output buffer with "garbage" to test that its data does not get read during encryption
let mut buf: alloc::vec::Vec<u8> = (0..pt.len()).map(|i| i as u8).collect();
let inout_buf = InOutBuf::new(pt, &mut buf).expect("pt and buf have the same length");
let mut buf: alloc::vec::Vec<u8> = (0..plaintext.len()).map(|i| i as u8).collect();
let inout_buf = InOutBuf::new(plaintext, &mut buf).expect("pt and buf have the same length");

let calc_tag = cipher
.encrypt_inout_detached(nonce, aad, inout_buf)
Expand All @@ -50,27 +87,43 @@ pub fn run_pass_test<C: AeadInOut>(
}

// Fill output buffer with "garbage"
buf.iter_mut().enumerate().for_each(|(i, v)| *v = i as u8);
buf.iter_mut()
.enumerate()
.for_each(|(i, v): (usize, &mut u8)| *v = i as u8);

let inout_buf = InOutBuf::new(ct, &mut buf).expect("ct and buf have the same length");
cipher
.decrypt_inout_detached(nonce, aad, inout_buf, tag)
.map_err(|_| "decrypt_inout_detached: decryption failure")?;
if pt != buf {
if plaintext != buf {
return Err("decrypt_inout_detached: plaintext mismatch");
}

Ok(())
}

/// Run AEAD test for the provided failing test vector
pub fn run_fail_test<C: AeadInOut>(
cipher: &C,
nonce: &Nonce<C>,
aad: &[u8],
ct: &[u8],
pub fn fail_test<C: AeadInOut + KeyInit>(
&TestVector {
key,
nonce,
aad,
ciphertext,
pass,
..
}: &TestVector,
) -> Result<(), &'static str> {
let res = cipher.decrypt(nonce, Payload { aad, msg: ct });
assert_eq!(pass, &[0]);
let nonce = nonce.try_into().expect("wrong nonce size");
let cipher = <C as KeyInit>::new_from_slice(key).expect("failed to initialize the cipher");

let res = cipher.decrypt(
nonce,
Payload {
aad,
msg: ciphertext,
},
);
if res.is_ok() {
Err("decryption must return error")
} else {
Expand All @@ -84,33 +137,29 @@ macro_rules! new_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use $crate::KeyInit;
use $crate::dev::blobby::Blob6Iterator;

let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob6Iterator::new(data).unwrap().enumerate() {
let [key, nonce, aad, pt, ct, status] = row.unwrap();
let key = key.try_into().expect("wrong key size");
let nonce = nonce.try_into().expect("wrong nonce size");
let cipher = <$cipher as KeyInit>::new(key);

let res = match status {
[0] => $crate::dev::run_fail_test(&cipher, nonce, aad, ct),
[1] => $crate::dev::run_pass_test(&cipher, nonce, aad, pt, ct),
_ => panic!("invalid value for pass flag"),
use $crate::dev::TestVector;

$crate::dev::blobby::parse_into_structs!(
include_bytes!(concat!("data/", $test_name, ".blb"));
static TEST_VECTORS: &[
TestVector { key, nonce, aad, plaintext, ciphertext, pass }
];
);

for (i, tv) in TEST_VECTORS.iter().enumerate() {
let pass = tv.pass[0] == 1;
let res = if pass {
$crate::dev::pass_test::<$cipher>(tv)
} else {
$crate::dev::fail_test::<$cipher>(tv)
};
let mut pass = status[0] == 1;

if let Err(reason) = res {
panic!(
"\n\
Failed test #{i}\n\
reason:\t{reason:?}\n\
key:\t{key:?}\n\
nonce:\t{nonce:?}\n\
aad:\t{aad:?}\n\
plaintext:\t{pt:?}\n\
ciphertext:\t{ct:?}\n\
pass:\t{pass}\n"
test vector:\t{tv:?}\n"
);
}
}
Expand Down
3 changes: 1 addition & 2 deletions aead/tests/dummy.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! This module defines dummy (horribly insecure!) AEAD implementations
//! to test implementation of the AEAD traits and helper macros in the `dev` module.
#![cfg(feature = "dev")]
use aead::{
AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, Nonce, Result, Tag, TagPosition,
array::Array, consts::U8,
Expand Down Expand Up @@ -169,7 +170,5 @@ impl AeadInOut for PostfixDummyAead {
}
}

#[cfg(feature = "dev")]
aead::new_test!(dummy_prefix, "prefix", PrefixDummyAead);
#[cfg(feature = "dev")]
aead::new_test!(dummy_postfix, "postfix", PostfixDummyAead);
7 changes: 5 additions & 2 deletions cipher/src/dev.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
mod block;
mod stream;
//! Development-related functionality
pub mod block;
pub mod stream;

pub use blobby;
Loading