Skip to content
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
1 change: 1 addition & 0 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 deoxys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ rust-version = "1.85"
[dependencies]
aead = { version = "0.6.0-rc.0", default-features = false }
aes = { version = "=0.9.0-pre.3", features = ["hazmat"], default-features = false }
inout = { version = "0.2.0-rc.4", default-features = false }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually this should drop and use aead::inout

subtle = { version = "2", default-features = false }
zeroize = { version = "1", optional = true, default-features = false }

Expand Down
150 changes: 129 additions & 21 deletions deoxys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ use aead::{
consts::U16,
};
use core::marker::PhantomData;
use inout::{InOut, InOutBuf};

/// Deoxys-I with 128-bit keys
pub type DeoxysI128 = Deoxys<modes::DeoxysI<deoxys_bc::DeoxysBc256>, deoxys_bc::DeoxysBc256>;
Expand Down Expand Up @@ -156,19 +157,19 @@ where

/// Encrypts the data in place with the specified parameters
/// Returns the tag
fn encrypt_in_place(
fn encrypt_inout(
nonce: &Array<u8, Self::NonceSize>,
associated_data: &[u8],
buffer: &mut [u8],
buffer: InOutBuf<'_, '_, u8>,
subkeys: &Array<DeoxysKey, B::SubkeysSize>,
) -> Tag;

/// Decrypts the data in place with the specified parameters
/// Returns an error if the tag verification fails
fn decrypt_in_place(
fn decrypt_inout(
nonce: &Array<u8, Self::NonceSize>,
associated_data: &[u8],
buffer: &mut [u8],
buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
subkeys: &Array<DeoxysKey, B::SubkeysSize>,
) -> Result<(), aead::Error>;
Expand All @@ -184,44 +185,40 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal {
fn precompute_subkeys(key: &Array<u8, Self::KeySize>) -> Array<DeoxysKey, Self::SubkeysSize>;

/// Encrypts a block of data in place.
fn encrypt_in_place(
block: &mut Block,
fn encrypt_inout(
mut block: InOut<'_, '_, Block>,
tweak: &Tweak,
subkeys: &Array<DeoxysKey, Self::SubkeysSize>,
) {
let keys = Self::key_schedule(tweak, subkeys);

for (b, k) in block.iter_mut().zip(keys[0].iter()) {
*b ^= k;
}
block.xor_in2out(&keys[0]);

for k in &keys[1..] {
aes::hazmat::cipher_round(block, k);
aes::hazmat::cipher_round(block.get_out(), k);
}
}

/// Decrypts a block of data in place.
fn decrypt_in_place(
block: &mut Block,
fn decrypt_inout(
mut block: InOut<'_, '_, Block>,
tweak: &Tweak,
subkeys: &Array<DeoxysKey, Self::SubkeysSize>,
) {
let mut keys = Self::key_schedule(tweak, subkeys);

let r = keys.len();

for (b, k) in block.iter_mut().zip(keys[r - 1].iter()) {
*b ^= k;
}
block.xor_in2out(&keys[r - 1]);

aes::hazmat::inv_mix_columns(block);
aes::hazmat::inv_mix_columns(block.get_out());

for k in keys[..r - 1].iter_mut().rev() {
aes::hazmat::inv_mix_columns(k);
aes::hazmat::equiv_inv_cipher_round(block, k);
aes::hazmat::equiv_inv_cipher_round(block.get_out(), k);
}

aes::hazmat::mix_columns(block);
aes::hazmat::mix_columns(block.get_out());
}
}

Expand Down Expand Up @@ -285,10 +282,10 @@ where
associated_data: &[u8],
buffer: &mut [u8],
) -> Result<Tag, Error> {
Ok(Tag::from(M::encrypt_in_place(
Ok(Tag::from(M::encrypt_inout(
nonce,
associated_data,
buffer,
buffer.into(),
&self.subkeys,
)))
}
Expand All @@ -300,7 +297,7 @@ where
buffer: &mut [u8],
tag: &Tag,
) -> Result<(), Error> {
M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys)
M::decrypt_inout(nonce, associated_data, buffer.into(), tag, &self.subkeys)
}
}

Expand All @@ -327,3 +324,114 @@ where
B: DeoxysBcType,
{
}

#[cfg(test)]
mod tests {
//! this module is here to test the inout behavior which is not currently exposed.
//! it will be once we port over to the API made in RustCrypto/traits#1793.
//!
//! This is to drop once https://github.com/RustCrypto/traits/pull/1797 is made available.
//!
//! It duplicates test vectors from `tests/deoxys_i_128.rs` and provides a mock buffer backing
//! for InOut.

use hex_literal::hex;

use super::*;

struct MockBuffer {
in_buf: [u8; 33],
out_buf: [u8; 33],
}

impl From<&[u8]> for MockBuffer {
fn from(buf: &[u8]) -> Self {
let mut in_buf = [0u8; 33];
in_buf.copy_from_slice(buf);
Self {
in_buf,
out_buf: [0u8; 33],
}
}
}

impl MockBuffer {
/// Get an [`InOutBuf`] from a [`MockBuffer`]
pub fn to_in_out_buf(&mut self) -> InOutBuf<'_, '_, u8> {
InOutBuf::new(self.in_buf.as_slice(), self.out_buf.as_mut_slice())
.expect("Invariant violation")
}
}

impl AsRef<[u8]> for MockBuffer {
fn as_ref(&self) -> &[u8] {
&self.out_buf
}
}

#[test]
fn test_deoxys_i_128_5() {
let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4");
let mut buffer = MockBuffer::from(&plaintext[..]);

let aad = [];

let key = hex!("101112131415161718191a1b1c1d1e1f");
let key = Array(key);

let nonce = hex!("202122232425262728292a2b2c2d2e2f");
let nonce = Array::try_from(&nonce[..8]).unwrap();

let ciphertext_expected =
hex!("cded5a43d3c76e942277c2a1517530ad66037897c985305ede345903ed7585a626");

let tag_expected: [u8; 16] = hex!("cbf5faa6b8398c47f4278d2019161776");

type M = modes::DeoxysI<deoxys_bc::DeoxysBc256>;
let cipher = DeoxysI128::new(&key);
let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys);

let ciphertext = buffer.as_ref();
assert_eq!(ciphertext, ciphertext_expected);
assert_eq!(tag, tag_expected);

let mut buffer = MockBuffer::from(buffer.as_ref());
M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys)
.expect("decryption failed");

assert_eq!(&plaintext[..], buffer.as_ref());
}

#[test]
fn test_deoxys_ii_128_5() {
let plaintext = hex!("06ac1756eccece62bd743fa80c299f7baa3872b556130f52265919494bdc136db3");
let mut buffer = MockBuffer::from(&plaintext[..]);

let aad = [];

let key = hex!("101112131415161718191a1b1c1d1e1f");
let key = Array(key);

let nonce = hex!("202122232425262728292a2b2c2d2e2f");
let nonce = Array::try_from(&nonce[..15]).unwrap();

let ciphertext_expected =
hex!("82bf241958b324ed053555d23315d3cc20935527fc970ff34a9f521a95e302136d");

let tag_expected: [u8; 16] = hex!("0eadc8612d5208c491e93005195e9769");

type M = modes::DeoxysII<deoxys_bc::DeoxysBc256>;
let cipher = DeoxysII128::new(&key);
let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys);

let ciphertext = buffer.as_ref();
assert_eq!(ciphertext, ciphertext_expected);
assert_eq!(tag, tag_expected);

let mut buffer = MockBuffer::from(buffer.as_ref());
M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys)
.expect("decryption failed");

assert_eq!(&plaintext[..], buffer.as_ref());
}
}
Loading