diff --git a/Cargo.lock b/Cargo.lock index 25e0977c..6daa4aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,8 +82,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cipher" version = "0.5.0-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71c893d5a1e8257048dbb29954d2e1f85f091a150304f1defe4ca2806da5d3f" +source = "git+https://github.com/RustCrypto/traits?branch=block_backends#b34c1d6a01c507fbe0186ac40307aa35ced4e41e" dependencies = [ "blobby", "crypto-common", @@ -103,8 +102,7 @@ dependencies = [ [[package]] name = "crypto-common" version = "0.2.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c070b79a496dccd931229780ad5bbedd535ceff6c3565605a8e440e18e1aa2b" +source = "git+https://github.com/RustCrypto/traits?branch=block_backends#b34c1d6a01c507fbe0186ac40307aa35ced4e41e" dependencies = [ "hybrid-array", ] diff --git a/Cargo.toml b/Cargo.toml index cbf5fa31..b519944a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,6 @@ members = [ [profile.dev] opt-level = 2 + +[patch.crates-io] +cipher = { git = "https://github.com/RustCrypto/traits", branch = "block_backends" } diff --git a/aria/src/aria128.rs b/aria/src/aria128.rs new file mode 100644 index 00000000..a56f61c5 --- /dev/null +++ b/aria/src/aria128.rs @@ -0,0 +1,69 @@ +use crate::{ + consts::{C1, C2, C3}, + utils::{a, fe, fo}, + Aria128, +}; +use cipher::{consts::U16, AlgorithmName, Key, KeyInit, KeySizeUser}; +use core::fmt; + +impl KeySizeUser for Aria128 { + type KeySize = U16; +} + +impl KeyInit for Aria128 { + fn new(key: &Key) -> Self { + let kl = u128::from_be_bytes(key[0..16].try_into().unwrap()); + let kr = u128::default(); + + let w0 = kl; + let w1 = fo(w0 ^ C1) ^ kr; + let w2 = fe(w1 ^ C2) ^ w0; + let w3 = fo(w2 ^ C3) ^ w1; + + let ek = [ + w0 ^ w1.rotate_right(19), + w1 ^ w2.rotate_right(19), + w2 ^ w3.rotate_right(19), + w3 ^ w0.rotate_right(19), + w0 ^ w1.rotate_right(31), + w1 ^ w2.rotate_right(31), + w2 ^ w3.rotate_right(31), + w3 ^ w0.rotate_right(31), + w0 ^ w1.rotate_left(61), + w1 ^ w2.rotate_left(61), + w2 ^ w3.rotate_left(61), + w3 ^ w0.rotate_left(61), + w0 ^ w1.rotate_left(31), + ]; + + let dk = [ + ek[12], + a(ek[11]), + a(ek[10]), + a(ek[9]), + a(ek[8]), + a(ek[7]), + a(ek[6]), + a(ek[5]), + a(ek[4]), + a(ek[3]), + a(ek[2]), + a(ek[1]), + ek[0], + ]; + + Self { ek, dk } + } +} + +impl fmt::Debug for Aria128 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Aria128 { ... }") + } +} + +impl AlgorithmName for Aria128 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Aria128") + } +} diff --git a/aria/src/aria192.rs b/aria/src/aria192.rs new file mode 100644 index 00000000..9e9218d4 --- /dev/null +++ b/aria/src/aria192.rs @@ -0,0 +1,74 @@ +use crate::{ + consts::{C1, C2, C3}, + utils::{a, fe, fo}, + Aria192, +}; +use cipher::{consts::U24, AlgorithmName, Key, KeyInit, KeySizeUser}; +use core::fmt; + +impl KeySizeUser for Aria192 { + type KeySize = U24; +} + +impl KeyInit for Aria192 { + fn new(key: &Key) -> Self { + let kl = u128::from_be_bytes(key[0..16].try_into().unwrap()); + let kr = u64::from_be_bytes(key[16..24].try_into().unwrap()); + let kr = (kr as u128) << 64; + + let w0 = kl; + let w1 = fo(w0 ^ C2) ^ kr; + let w2 = fe(w1 ^ C3) ^ w0; + let w3 = fo(w2 ^ C1) ^ w1; + + let ek = [ + w0 ^ w1.rotate_right(19), + w1 ^ w2.rotate_right(19), + w2 ^ w3.rotate_right(19), + w3 ^ w0.rotate_right(19), + w0 ^ w1.rotate_right(31), + w1 ^ w2.rotate_right(31), + w2 ^ w3.rotate_right(31), + w3 ^ w0.rotate_right(31), + w0 ^ w1.rotate_left(61), + w1 ^ w2.rotate_left(61), + w2 ^ w3.rotate_left(61), + w3 ^ w0.rotate_left(61), + w0 ^ w1.rotate_left(31), + w1 ^ w2.rotate_left(31), + w2 ^ w3.rotate_left(31), + ]; + + let dk = [ + ek[14], + a(ek[13]), + a(ek[12]), + a(ek[11]), + a(ek[10]), + a(ek[9]), + a(ek[8]), + a(ek[7]), + a(ek[6]), + a(ek[5]), + a(ek[4]), + a(ek[3]), + a(ek[2]), + a(ek[1]), + ek[0], + ]; + + Self { ek, dk } + } +} + +impl fmt::Debug for Aria192 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Aria192 { ... }") + } +} + +impl AlgorithmName for Aria192 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Aria192") + } +} diff --git a/aria/src/aria256.rs b/aria/src/aria256.rs new file mode 100644 index 00000000..728792e7 --- /dev/null +++ b/aria/src/aria256.rs @@ -0,0 +1,77 @@ +use crate::{ + consts::{C1, C2, C3}, + utils::{a, fe, fo}, + Aria256, +}; +use cipher::{consts::U32, AlgorithmName, Key, KeyInit, KeySizeUser}; +use core::fmt; + +impl KeySizeUser for Aria256 { + type KeySize = U32; +} + +impl KeyInit for Aria256 { + fn new(key: &Key) -> Self { + let kl = u128::from_be_bytes(key[0..16].try_into().unwrap()); + let kr = u128::from_be_bytes(key[16..32].try_into().unwrap()); + + let w0 = kl; + let w1 = fo(w0 ^ C3) ^ kr; + let w2 = fe(w1 ^ C1) ^ w0; + let w3 = fo(w2 ^ C2) ^ w1; + + let ek = [ + w0 ^ w1.rotate_right(19), + w1 ^ w2.rotate_right(19), + w2 ^ w3.rotate_right(19), + w3 ^ w0.rotate_right(19), + w0 ^ w1.rotate_right(31), + w1 ^ w2.rotate_right(31), + w2 ^ w3.rotate_right(31), + w3 ^ w0.rotate_right(31), + w0 ^ w1.rotate_left(61), + w1 ^ w2.rotate_left(61), + w2 ^ w3.rotate_left(61), + w3 ^ w0.rotate_left(61), + w0 ^ w1.rotate_left(31), + w1 ^ w2.rotate_left(31), + w2 ^ w3.rotate_left(31), + w3 ^ w0.rotate_left(31), + w0 ^ w1.rotate_left(19), + ]; + + let dk = [ + ek[16], + a(ek[15]), + a(ek[14]), + a(ek[13]), + a(ek[12]), + a(ek[11]), + a(ek[10]), + a(ek[9]), + a(ek[8]), + a(ek[7]), + a(ek[6]), + a(ek[5]), + a(ek[4]), + a(ek[3]), + a(ek[2]), + a(ek[1]), + ek[0], + ]; + + Self { ek, dk } + } +} + +impl fmt::Debug for Aria256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Aria256 { ... }") + } +} + +impl AlgorithmName for Aria256 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Aria256") + } +} diff --git a/aria/src/lib.rs b/aria/src/lib.rs index ff2ad66a..5d4cb711 100644 --- a/aria/src/lib.rs +++ b/aria/src/lib.rs @@ -10,8 +10,11 @@ //! //! # Examples //! ``` -//! use aria::cipher::array::Array; -//! use aria::cipher::{Key, Block, BlockCipherEncrypt, BlockCipherDecrypt, KeyInit}; +//! use aria::cipher::{ +//! array::Array, +//! block::{BlockCipherDecrypt, BlockCipherEncrypt}, +//! Block, Key, KeyInit, +//! }; //! use aria::Aria128; //! //! let key = Array::from([0u8; 16]); @@ -36,7 +39,7 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] mod consts; @@ -44,324 +47,111 @@ mod consts; pub use cipher; use cipher::{ - consts::{U16, U24, U32}, - AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U16}, + inout::InOut, + Block, BlockSizeUser, ParBlocksSizeUser, }; -use core::fmt; #[cfg(feature = "zeroize")] use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::consts::{C1, C2, C3, DIFFUSE_CONSTS, SB1, SB2, SB3, SB4}; - -#[inline(always)] -fn diffuse(x: [u8; 16]) -> u128 { - DIFFUSE_CONSTS - .iter() - .zip(x) - .map(|(a, b)| a * b as u128) - .fold(0, |a, v| a ^ v) -} - -#[inline(always)] -fn a(x128: u128) -> u128 { - diffuse(x128.to_be_bytes()) -} - -fn sl2(x128: u128) -> u128 { - let x = x128.to_be_bytes(); - let y = [ - SB3[x[0] as usize], - SB4[x[1] as usize], - SB1[x[2] as usize], - SB2[x[3] as usize], - SB3[x[4] as usize], - SB4[x[5] as usize], - SB1[x[6] as usize], - SB2[x[7] as usize], - SB3[x[8] as usize], - SB4[x[9] as usize], - SB1[x[10] as usize], - SB2[x[11] as usize], - SB3[x[12] as usize], - SB4[x[13] as usize], - SB1[x[14] as usize], - SB2[x[15] as usize], - ]; - u128::from_be_bytes(y) +mod aria128; +mod aria192; +mod aria256; +mod utils; + +use utils::{fe, fo, sl2}; + +/// Generic implementation of the ARIA block cipher. +/// +/// It can be initialized only with `RK` being equal to 13 (ARIA-128), +/// 15 (ARIA-192), or 17 (ARIA-256). +#[derive(Clone)] +pub struct Aria { + /// Encrypting subkeys. + ek: [u128; RK], + /// Encrypting subkeys. + dk: [u128; RK], } -fn fo(x128: u128) -> u128 { - let x = x128.to_be_bytes(); - diffuse([ - SB1[x[0] as usize], - SB2[x[1] as usize], - SB3[x[2] as usize], - SB4[x[3] as usize], - SB1[x[4] as usize], - SB2[x[5] as usize], - SB3[x[6] as usize], - SB4[x[7] as usize], - SB1[x[8] as usize], - SB2[x[9] as usize], - SB3[x[10] as usize], - SB4[x[11] as usize], - SB1[x[12] as usize], - SB2[x[13] as usize], - SB3[x[14] as usize], - SB4[x[15] as usize], - ]) +impl BlockSizeUser for Aria { + type BlockSize = U16; } -fn fe(x128: u128) -> u128 { - let x = x128.to_be_bytes(); - diffuse([ - SB3[x[0] as usize], - SB4[x[1] as usize], - SB1[x[2] as usize], - SB2[x[3] as usize], - SB3[x[4] as usize], - SB4[x[5] as usize], - SB1[x[6] as usize], - SB2[x[7] as usize], - SB3[x[8] as usize], - SB4[x[9] as usize], - SB1[x[10] as usize], - SB2[x[11] as usize], - SB3[x[12] as usize], - SB4[x[13] as usize], - SB1[x[14] as usize], - SB2[x[15] as usize], - ]) +impl ParBlocksSizeUser for Aria { + type ParBlocksSize = U1; } -impl KeyInit for Aria128 { - fn new(key: &Key) -> Self { - let kl = u128::from_be_bytes(key[0..16].try_into().unwrap()); - let kr = u128::default(); - - let w0 = kl; - let w1 = fo(w0 ^ C1) ^ kr; - let w2 = fe(w1 ^ C2) ^ w0; - let w3 = fo(w2 ^ C3) ^ w1; - - let ek = [ - w0 ^ w1.rotate_right(19), - w1 ^ w2.rotate_right(19), - w2 ^ w3.rotate_right(19), - w3 ^ w0.rotate_right(19), - w0 ^ w1.rotate_right(31), - w1 ^ w2.rotate_right(31), - w2 ^ w3.rotate_right(31), - w3 ^ w0.rotate_right(31), - w0 ^ w1.rotate_left(61), - w1 ^ w2.rotate_left(61), - w2 ^ w3.rotate_left(61), - w3 ^ w0.rotate_left(61), - w0 ^ w1.rotate_left(31), - ]; - - let dk = [ - ek[12], - a(ek[11]), - a(ek[10]), - a(ek[9]), - a(ek[8]), - a(ek[7]), - a(ek[6]), - a(ek[5]), - a(ek[4]), - a(ek[3]), - a(ek[2]), - a(ek[1]), - ek[0], - ]; - - Self { ek, dk } +impl BlockCipherEncrypt for Aria { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) } } -impl KeyInit for Aria192 { - fn new(key: &Key) -> Self { - let kl = u128::from_be_bytes(key[0..16].try_into().unwrap()); - let kr = u64::from_be_bytes(key[16..24].try_into().unwrap()); - let kr = (kr as u128) << 64; - - let w0 = kl; - let w1 = fo(w0 ^ C2) ^ kr; - let w2 = fe(w1 ^ C3) ^ w0; - let w3 = fo(w2 ^ C1) ^ w1; +impl BlockCipherEncBackend for Aria { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut p0 = u128::from_be_bytes((*block.get_in()).into()); + let mut p1; - let ek = [ - w0 ^ w1.rotate_right(19), - w1 ^ w2.rotate_right(19), - w2 ^ w3.rotate_right(19), - w3 ^ w0.rotate_right(19), - w0 ^ w1.rotate_right(31), - w1 ^ w2.rotate_right(31), - w2 ^ w3.rotate_right(31), - w3 ^ w0.rotate_right(31), - w0 ^ w1.rotate_left(61), - w1 ^ w2.rotate_left(61), - w2 ^ w3.rotate_left(61), - w3 ^ w0.rotate_left(61), - w0 ^ w1.rotate_left(31), - w1 ^ w2.rotate_left(31), - w2 ^ w3.rotate_left(31), - ]; + for i in (0..RK - 3).step_by(2) { + p1 = fo(p0 ^ self.ek[i]); + p0 = fe(p1 ^ self.ek[i + 1]); + } - let dk = [ - ek[14], - a(ek[13]), - a(ek[12]), - a(ek[11]), - a(ek[10]), - a(ek[9]), - a(ek[8]), - a(ek[7]), - a(ek[6]), - a(ek[5]), - a(ek[4]), - a(ek[3]), - a(ek[2]), - a(ek[1]), - ek[0], - ]; + let p1 = fo(p0 ^ self.ek[RK - 3]); + let c = sl2(p1 ^ self.ek[RK - 2]) ^ self.ek[RK - 1]; - Self { ek, dk } + block.get_out().copy_from_slice(&c.to_be_bytes()); } } -impl KeyInit for Aria256 { - fn new(key: &Key) -> Self { - let kl = u128::from_be_bytes(key[0..16].try_into().unwrap()); - let kr = u128::from_be_bytes(key[16..32].try_into().unwrap()); - - let w0 = kl; - let w1 = fo(w0 ^ C3) ^ kr; - let w2 = fe(w1 ^ C1) ^ w0; - let w3 = fo(w2 ^ C2) ^ w1; - - let ek = [ - w0 ^ w1.rotate_right(19), - w1 ^ w2.rotate_right(19), - w2 ^ w3.rotate_right(19), - w3 ^ w0.rotate_right(19), - w0 ^ w1.rotate_right(31), - w1 ^ w2.rotate_right(31), - w2 ^ w3.rotate_right(31), - w3 ^ w0.rotate_right(31), - w0 ^ w1.rotate_left(61), - w1 ^ w2.rotate_left(61), - w2 ^ w3.rotate_left(61), - w3 ^ w0.rotate_left(61), - w0 ^ w1.rotate_left(31), - w1 ^ w2.rotate_left(31), - w2 ^ w3.rotate_left(31), - w3 ^ w0.rotate_left(31), - w0 ^ w1.rotate_left(19), - ]; - - let dk = [ - ek[16], - a(ek[15]), - a(ek[14]), - a(ek[13]), - a(ek[12]), - a(ek[11]), - a(ek[10]), - a(ek[9]), - a(ek[8]), - a(ek[7]), - a(ek[6]), - a(ek[5]), - a(ek[4]), - a(ek[3]), - a(ek[2]), - a(ek[1]), - ek[0], - ]; - - Self { ek, dk } +impl BlockCipherDecrypt for Aria { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) } } -macro_rules! impl_aria { - ($name:ident, $subkey_size:literal, $key_size:ty, $doc:literal) => { - #[doc = $doc] - #[derive(Clone)] - pub struct $name { - /// Encrypting subkeys. - ek: [u128; $subkey_size], - /// Encrypting subkeys. - dk: [u128; $subkey_size], - } - impl BlockCipher for $name {} +impl BlockCipherDecBackend for Aria { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut c0 = u128::from_be_bytes((*block.get_in()).into()); + let mut c1; - impl KeySizeUser for $name { - type KeySize = $key_size; + for i in (0..RK - 3).step_by(2) { + c1 = fo(c0 ^ self.dk[i]); + c0 = fe(c1 ^ self.dk[i + 1]); } - impl fmt::Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(concat!(stringify!($name), " { ... }")) - } - } + let c1 = fo(c0 ^ self.dk[RK - 3]); + let p = sl2(c1 ^ self.dk[RK - 2]) ^ self.dk[RK - 1]; - impl AlgorithmName for $name { - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(stringify!($name)) - } - } + block.get_out().copy_from_slice(&p.to_be_bytes()); + } +} +impl Drop for Aria { + fn drop(&mut self) { #[cfg(feature = "zeroize")] - #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] - impl Drop for $name { - fn drop(&mut self) { - self.ek.zeroize(); - self.dk.zeroize(); - } + { + self.ek.zeroize(); + self.dk.zeroize(); } - - #[cfg(feature = "zeroize")] - #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] - impl ZeroizeOnDrop for $name {} - - cipher::impl_simple_block_encdec!( - $name, U16, cipher, block, - encrypt: { - let mut p0 = u128::from_be_bytes((*block.get_in()).into()); - let mut p1; - - for i in (0..$subkey_size - 3).step_by(2) { - p1 = fo(p0 ^ cipher.ek[i]); - p0 = fe(p1 ^ cipher.ek[i + 1]); - } - - let p1 = fo(p0 ^ cipher.ek[$subkey_size - 3]); - let c = sl2(p1 ^ cipher.ek[$subkey_size - 2]) ^ cipher.ek[$subkey_size - 1]; - - block.get_out().copy_from_slice(&c.to_be_bytes()); - } - decrypt: { - let mut c0 = u128::from_be_bytes((*block.get_in()).into()); - let mut c1; - - for i in (0..$subkey_size - 3).step_by(2) { - c1 = fo(c0 ^ cipher.dk[i]); - c0 = fe(c1 ^ cipher.dk[i + 1]); - } - - let c1 = fo(c0 ^ cipher.dk[$subkey_size - 3]); - let p = sl2(c1 ^ cipher.dk[$subkey_size - 2]) ^ cipher.dk[$subkey_size - 1]; - - block.get_out().copy_from_slice(&p.to_be_bytes()); - } - ); - - }; + } } -impl_aria!(Aria128, 13, U16, "Aria-128 block cipher instance."); -impl_aria!(Aria192, 15, U24, "Aria-192 block cipher instance."); -impl_aria!(Aria256, 17, U32, "Aria-256 block cipher instance."); +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for Aria {} + +/// ARIA-128 block cipher instance. +pub type Aria128 = Aria<13>; +/// ARIA-192 block cipher instance. +pub type Aria192 = Aria<15>; +/// ARIA-256 block cipher instance. +pub type Aria256 = Aria<17>; diff --git a/aria/src/utils.rs b/aria/src/utils.rs new file mode 100644 index 00000000..960c1d99 --- /dev/null +++ b/aria/src/utils.rs @@ -0,0 +1,82 @@ +use crate::consts::{DIFFUSE_CONSTS, SB1, SB2, SB3, SB4}; + +#[inline(always)] +fn diffuse(x: [u8; 16]) -> u128 { + DIFFUSE_CONSTS + .iter() + .zip(x) + .map(|(a, b)| a * b as u128) + .fold(0, |a, v| a ^ v) +} + +#[inline(always)] +pub(crate) fn a(x128: u128) -> u128 { + diffuse(x128.to_be_bytes()) +} + +pub(crate) fn sl2(x128: u128) -> u128 { + let x = x128.to_be_bytes(); + let y = [ + SB3[x[0] as usize], + SB4[x[1] as usize], + SB1[x[2] as usize], + SB2[x[3] as usize], + SB3[x[4] as usize], + SB4[x[5] as usize], + SB1[x[6] as usize], + SB2[x[7] as usize], + SB3[x[8] as usize], + SB4[x[9] as usize], + SB1[x[10] as usize], + SB2[x[11] as usize], + SB3[x[12] as usize], + SB4[x[13] as usize], + SB1[x[14] as usize], + SB2[x[15] as usize], + ]; + u128::from_be_bytes(y) +} + +pub(crate) fn fo(x128: u128) -> u128 { + let x = x128.to_be_bytes(); + diffuse([ + SB1[x[0] as usize], + SB2[x[1] as usize], + SB3[x[2] as usize], + SB4[x[3] as usize], + SB1[x[4] as usize], + SB2[x[5] as usize], + SB3[x[6] as usize], + SB4[x[7] as usize], + SB1[x[8] as usize], + SB2[x[9] as usize], + SB3[x[10] as usize], + SB4[x[11] as usize], + SB1[x[12] as usize], + SB2[x[13] as usize], + SB3[x[14] as usize], + SB4[x[15] as usize], + ]) +} + +pub(crate) fn fe(x128: u128) -> u128 { + let x = x128.to_be_bytes(); + diffuse([ + SB3[x[0] as usize], + SB4[x[1] as usize], + SB1[x[2] as usize], + SB2[x[3] as usize], + SB3[x[4] as usize], + SB4[x[5] as usize], + SB1[x[6] as usize], + SB2[x[7] as usize], + SB3[x[8] as usize], + SB4[x[9] as usize], + SB1[x[10] as usize], + SB2[x[11] as usize], + SB3[x[12] as usize], + SB4[x[13] as usize], + SB1[x[14] as usize], + SB2[x[15] as usize], + ]) +} diff --git a/aria/tests/mod.rs b/aria/tests/mod.rs index f9dcdb8f..e0563431 100644 --- a/aria/tests/mod.rs +++ b/aria/tests/mod.rs @@ -1,5 +1,9 @@ use aria::{Aria128, Aria192, Aria256}; -use cipher::{array::Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit}; +use cipher::{ + array::Array, + block::{BlockCipherDecrypt, BlockCipherEncrypt}, + KeyInit, +}; use hex_literal::hex; /// Test vector from RFC 5794, Appendix A.1 diff --git a/belt-block/src/cipher_impl.rs b/belt-block/src/cipher_impl.rs index 4a8e5c26..16163f4c 100644 --- a/belt-block/src/cipher_impl.rs +++ b/belt-block/src/cipher_impl.rs @@ -1,6 +1,11 @@ use crate::{belt_block_raw, from_u32, g13, g21, g5, key_idx, to_u32}; -use cipher::consts::{U16, U32}; -use cipher::{inout::InOut, AlgorithmName, Block, BlockCipher, Key, KeyInit, KeySizeUser}; +use cipher::block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, +}; +use cipher::consts::{U1, U16, U32}; +use cipher::{inout::InOut, AlgorithmName, Block, Key, KeyInit, KeySizeUser}; +use cipher::{BlockSizeUser, ParBlocksSizeUser}; use core::{fmt, mem::swap, num::Wrapping}; #[cfg(feature = "zeroize")] @@ -13,10 +18,35 @@ pub struct BeltBlock { key: [u32; 8], } -impl BeltBlock { - /// Encryption as described in section 6.1.3 +impl KeySizeUser for BeltBlock { + type KeySize = U32; +} + +impl KeyInit for BeltBlock { + fn new(key: &Key) -> Self { + Self { key: to_u32(key) } + } +} + +impl BlockSizeUser for BeltBlock { + type BlockSize = U16; +} + +impl ParBlocksSizeUser for BeltBlock { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for BeltBlock { #[inline] - fn encrypt(&self, mut block: InOut<'_, '_, Block>) { + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for BeltBlock { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + // Encryption as described in section 6.1.3 // Steps 1 and 4 let x = to_u32(block.get_in()); let y = belt_block_raw(x, &self.key); @@ -25,10 +55,18 @@ impl BeltBlock { // 6) Y ← b ‖ d ‖ a ‖ c *block_out = from_u32(&y).into(); } +} - /// Decryption as described in section 6.1.4 +impl BlockCipherDecrypt for BeltBlock { #[inline] - fn decrypt(&self, mut block: InOut<'_, '_, Block>) { + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for BeltBlock { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { let key = &self.key; let block_in: [u32; 4] = to_u32(block.get_in()); // Steps 1 and 4 @@ -72,18 +110,6 @@ impl BeltBlock { } } -impl BlockCipher for BeltBlock {} - -impl KeySizeUser for BeltBlock { - type KeySize = U32; -} - -impl KeyInit for BeltBlock { - fn new(key: &Key) -> Self { - Self { key: to_u32(key) } - } -} - impl AlgorithmName for BeltBlock { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("BeltBlock") @@ -91,7 +117,6 @@ impl AlgorithmName for BeltBlock { } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl Drop for BeltBlock { fn drop(&mut self) { self.key.zeroize(); @@ -99,15 +124,4 @@ impl Drop for BeltBlock { } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for BeltBlock {} - -cipher::impl_simple_block_encdec!( - BeltBlock, U16, cipher, block, - encrypt: { - cipher.encrypt(block); - } - decrypt: { - cipher.decrypt(block); - } -); diff --git a/belt-block/src/lib.rs b/belt-block/src/lib.rs index 321bfc44..cc7ae331 100644 --- a/belt-block/src/lib.rs +++ b/belt-block/src/lib.rs @@ -17,7 +17,7 @@ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] #![forbid(unsafe_code)] diff --git a/belt-block/tests/mod.rs b/belt-block/tests/mod.rs index ff649dc7..cc1c3b16 100644 --- a/belt-block/tests/mod.rs +++ b/belt-block/tests/mod.rs @@ -3,7 +3,10 @@ use belt_block::{belt_block_raw, belt_wblock_dec, belt_wblock_enc}; #[cfg(feature = "cipher")] use belt_block::{ - cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit}, + cipher::{ + block::{BlockCipherDecrypt, BlockCipherEncrypt}, + KeyInit, + }, BeltBlock, }; use hex_literal::hex; diff --git a/blowfish/src/lib.rs b/blowfish/src/lib.rs index ad18fbe8..d7b38705 100644 --- a/blowfish/src/lib.rs +++ b/blowfish/src/lib.rs @@ -16,15 +16,20 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] pub use cipher; use byteorder::{ByteOrder, BE, LE}; use cipher::{ - consts::{U56, U8}, - AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U56, U8}, + AlgorithmName, Block, BlockSizeUser, InOut, InvalidLength, Key, KeyInit, KeySizeUser, + ParBlocksSizeUser, }; use core::fmt; use core::marker::PhantomData; @@ -120,8 +125,6 @@ impl Blowfish { } } -impl BlockCipher for Blowfish {} - impl KeySizeUser for Blowfish { type KeySize = U56; } @@ -141,6 +144,48 @@ impl KeyInit for Blowfish { } } +impl BlockSizeUser for Blowfish { + type BlockSize = U8; +} + +impl ParBlocksSizeUser for Blowfish { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for Blowfish { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for Blowfish { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut b = [0u32; 2]; + T::read_u32_into(block.get_in(), &mut b); + b = self.encrypt(b); + T::write_u32_into(&b, block.get_out()); + } +} + +impl BlockCipherDecrypt for Blowfish { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for Blowfish { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut b = [0u32; 2]; + T::read_u32_into(block.get_in(), &mut b); + b = self.decrypt(b); + T::write_u32_into(&b, block.get_out()); + } +} + impl fmt::Debug for Blowfish { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Blowfish { ... }") @@ -165,35 +210,19 @@ impl AlgorithmName for Blowfish { } } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl Drop for Blowfish { fn drop(&mut self) { - self.s.zeroize(); - self.p.zeroize(); + #[cfg(feature = "zeroize")] + { + self.s.zeroize(); + self.p.zeroize(); + } } } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for Blowfish {} -cipher::impl_simple_block_encdec!( - Blowfish, U8, cipher, block, - encrypt: { - let mut b = [0u32; 2]; - T::read_u32_into(block.get_in(), &mut b); - b = cipher.encrypt(b); - T::write_u32_into(&b, block.get_out()); - } - decrypt: { - let mut b = [0u32; 2]; - T::read_u32_into(block.get_in(), &mut b); - b = cipher.decrypt(b); - T::write_u32_into(&b, block.get_out()); - } -); - /// Bcrypt extension of blowfish #[cfg(feature = "bcrypt")] impl Blowfish { diff --git a/camellia/src/camellia.rs b/camellia/src/camellia.rs deleted file mode 100644 index 71bf9f56..00000000 --- a/camellia/src/camellia.rs +++ /dev/null @@ -1,352 +0,0 @@ -// -// Based on src/lib/block/camellia/camellia.cpp from https://github.com/randombit/botan -// Revision: 32bf9784bd6ee29cb3ffa173f0a734e9edce2dac -// - -/* - * Camellia - * (C) 2012,2020 Jack Lloyd - * - * Botan is released under the Simplified BSD License (see license.txt) - */ - -use core::fmt; - -use byteorder::{ByteOrder, BE}; -use cipher::{ - consts::{U16, U24, U32}, - AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, -}; - -#[cfg(feature = "zeroize")] -use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; - -use crate::consts::{SBOXES, SIGMAS}; - -/// F-function of component of Camellia defined in RFC 3713. -fn f(input: u64, key: u64) -> u64 { - let x = (input ^ key).to_be_bytes(); - - let z1 = 0x0101_0100_0100_0001 * u64::from(SBOXES[0][usize::from(x[0])]); - let z2 = 0x0001_0101_0101_0000 * u64::from(SBOXES[1][usize::from(x[1])]); - let z3 = 0x0100_0101_0001_0100 * u64::from(SBOXES[2][usize::from(x[2])]); - let z4 = 0x0101_0001_0000_0101 * u64::from(SBOXES[3][usize::from(x[3])]); - let z5 = 0x0001_0101_0001_0101 * u64::from(SBOXES[1][usize::from(x[4])]); - let z6 = 0x0100_0101_0100_0101 * u64::from(SBOXES[2][usize::from(x[5])]); - let z7 = 0x0101_0001_0101_0001 * u64::from(SBOXES[3][usize::from(x[6])]); - let z8 = 0x0101_0100_0101_0100 * u64::from(SBOXES[0][usize::from(x[7])]); - - z1 ^ z2 ^ z3 ^ z4 ^ z5 ^ z6 ^ z7 ^ z8 -} - -/// FL-function of component of Camellia defined in RFC 3713. -fn fl(input: u64, key: u64) -> u64 { - let mut x1 = u32::try_from(input >> 32).unwrap(); - let mut x2 = u32::try_from(input & 0xffff_ffff).unwrap(); - - let k1 = u32::try_from(key >> 32).unwrap(); - let k2 = u32::try_from(key & 0xffff_ffff).unwrap(); - - x2 ^= (x1 & k1).rotate_left(1); - x1 ^= x2 | k2; - - (u64::from(x1) << 32) | u64::from(x2) -} - -/// FLINV-function of component of Camellia defined in RFC 3713. -fn flinv(input: u64, key: u64) -> u64 { - let mut y1 = u32::try_from(input >> 32).unwrap(); - let mut y2 = u32::try_from(input & 0xffff_ffff).unwrap(); - - let k1 = u32::try_from(key >> 32).unwrap(); - let k2 = u32::try_from(key & 0xffff_ffff).unwrap(); - - y1 ^= y2 | k2; - y2 ^= (y1 & k1).rotate_left(1); - - (u64::from(y1) << 32) | u64::from(y2) -} - -macro_rules! set_kl { - ($key:expr) => { - ( - u64::from_be_bytes($key[0..8].try_into().unwrap()), - u64::from_be_bytes($key[8..16].try_into().unwrap()), - ) - }; -} - -fn set_ka(kl: (u64, u64), kr: (u64, u64)) -> (u64, u64) { - let mut d1 = kl.0 ^ kr.0; - let mut d2 = kl.1 ^ kr.1; - d2 ^= f(d1, SIGMAS[0]); - d1 ^= f(d2, SIGMAS[1]); - d1 ^= kl.0; - d2 ^= kl.1; - d2 ^= f(d1, SIGMAS[2]); - d1 ^= f(d2, SIGMAS[3]); - - (d1, d2) -} - -fn set_kb(ka: (u64, u64), kr: (u64, u64)) -> (u64, u64) { - let mut d1 = ka.0 ^ kr.0; - let mut d2 = ka.1 ^ kr.1; - d2 ^= f(d1, SIGMAS[4]); - d1 ^= f(d2, SIGMAS[5]); - - (d1, d2) -} - -/// Performs rotate left and taking the higher-half of it. -fn rotate_left_high(val: (u64, u64), mut shift: u8) -> u64 { - if shift >= 64 { - shift -= 64; - } - - (val.0 << shift) | (val.1 >> (64 - shift)) -} - -/// Performs rotate left and taking the lower-half of it. -fn rotate_left_low(val: (u64, u64), mut shift: u8) -> u64 { - if shift >= 64 { - shift -= 64; - } - - (val.0 >> (64 - shift)) | (val.1 << shift) -} - -impl Camellia128 { - fn gen_subkeys(kl: (u64, u64), ka: (u64, u64)) -> Self { - let mut k = [u64::default(); 26]; - - k[0] = kl.0; - k[1] = kl.1; - - k[2] = ka.0; - k[3] = ka.1; - k[4] = rotate_left_high(kl, 15); - k[5] = rotate_left_low(kl, 15); - k[6] = rotate_left_high(ka, 15); - k[7] = rotate_left_low(ka, 15); - - k[8] = rotate_left_high(ka, 30); - k[9] = rotate_left_low(ka, 30); - - k[10] = rotate_left_high(kl, 45); - k[11] = rotate_left_low(kl, 45); - k[12] = rotate_left_high(ka, 45); - k[13] = rotate_left_low(kl, 60); - k[14] = rotate_left_high(ka, 60); - k[15] = rotate_left_low(ka, 60); - - k[16] = rotate_left_low(kl, 77); - k[17] = rotate_left_high(kl, 77); - - k[18] = rotate_left_low(kl, 94); - k[19] = rotate_left_high(kl, 94); - k[20] = rotate_left_low(ka, 94); - k[21] = rotate_left_high(ka, 94); - k[22] = rotate_left_low(kl, 111); - k[23] = rotate_left_high(kl, 111); - - k[24] = rotate_left_low(ka, 111); - k[25] = rotate_left_high(ka, 111); - - Self { k } - } -} - -macro_rules! impl_gen_subkeys { - ($name:ident) => { - impl $name { - fn gen_subkeys(kl: (u64, u64), kr: (u64, u64), ka: (u64, u64), kb: (u64, u64)) -> Self { - let mut k = [u64::default(); 34]; - - k[0] = kl.0; - k[1] = kl.1; - - k[2] = kb.0; - k[3] = kb.1; - k[4] = rotate_left_high(kr, 15); - k[5] = rotate_left_low(kr, 15); - k[6] = rotate_left_high(ka, 15); - k[7] = rotate_left_low(ka, 15); - - k[8] = rotate_left_high(kr, 30); - k[9] = rotate_left_low(kr, 30); - - k[10] = rotate_left_high(kb, 30); - k[11] = rotate_left_low(kb, 30); - k[12] = rotate_left_high(kl, 45); - k[13] = rotate_left_low(kl, 45); - k[14] = rotate_left_high(ka, 45); - k[15] = rotate_left_low(ka, 45); - - k[16] = rotate_left_high(kl, 60); - k[17] = rotate_left_low(kl, 60); - - k[18] = rotate_left_high(kr, 60); - k[19] = rotate_left_low(kr, 60); - k[20] = rotate_left_high(kb, 60); - k[21] = rotate_left_low(kb, 60); - k[22] = rotate_left_low(kl, 77); - k[23] = rotate_left_high(kl, 77); - - k[24] = rotate_left_low(ka, 77); - k[25] = rotate_left_high(ka, 77); - - k[26] = rotate_left_low(kr, 94); - k[27] = rotate_left_high(kr, 94); - k[28] = rotate_left_low(ka, 94); - k[29] = rotate_left_high(ka, 94); - k[30] = rotate_left_low(kl, 111); - k[31] = rotate_left_high(kl, 111); - - k[32] = rotate_left_low(kb, 111); - k[33] = rotate_left_high(kb, 111); - - Self { k } - } - } - }; -} - -impl_gen_subkeys!(Camellia192); -impl_gen_subkeys!(Camellia256); - -impl KeyInit for Camellia128 { - fn new(key: &Key) -> Self { - let kl = set_kl!(key); - let kr = (u64::default(), u64::default()); - - let ka = set_ka(kl, kr); - - Self::gen_subkeys(kl, ka) - } -} - -impl KeyInit for Camellia192 { - fn new(key: &Key) -> Self { - let kl = set_kl!(key); - let kr = u64::from_be_bytes(key[16..24].try_into().unwrap()); - let kr = (kr, !kr); - - let ka = set_ka(kl, kr); - let kb = set_kb(ka, kr); - - Self::gen_subkeys(kl, kr, ka, kb) - } -} - -impl KeyInit for Camellia256 { - fn new(key: &Key) -> Self { - let kl = set_kl!(key); - let kr = ( - u64::from_be_bytes(key[16..24].try_into().unwrap()), - u64::from_be_bytes(key[24..32].try_into().unwrap()), - ); - - let ka = set_ka(kl, kr); - let kb = set_kb(ka, kr); - - Self::gen_subkeys(kl, kr, ka, kb) - } -} - -macro_rules! impl_camellia { - ($name:ident, $subkey_size:literal, $key_size:ty, $doc:literal) => { - #[doc = $doc] - #[derive(Clone)] - pub struct $name { - /// Subkeys. - k: [u64; $subkey_size], - } - - impl BlockCipher for $name {} - - impl KeySizeUser for $name { - type KeySize = $key_size; - } - - impl fmt::Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(concat!(stringify!($name), " { ... }")) - } - } - - impl AlgorithmName for $name { - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(stringify!($name)) - } - } - - #[cfg(feature = "zeroize")] - #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] - impl Drop for $name { - fn drop(&mut self) { - self.k.zeroize(); - } - } - - #[cfg(feature = "zeroize")] - #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] - impl ZeroizeOnDrop for $name {} - - cipher::impl_simple_block_encdec!( - $name, U16, cipher, block, - encrypt: { - let b = block.get_in(); - let mut d1 = u64::from_be_bytes(b[0..8].try_into().unwrap()); - let mut d2 = u64::from_be_bytes(b[8..16].try_into().unwrap()); - - d1 ^= cipher.k[0]; - d2 ^= cipher.k[1]; - - for i in (2..$subkey_size - 2).step_by(2) { - if i % 8 == 0 { - d1 = fl(d1, cipher.k[i]); - d2 = flinv(d2, cipher.k[i + 1]); - - continue; - } - d2 ^= f(d1, cipher.k[i]); - d1 ^= f(d2, cipher.k[i + 1]); - } - - d2 ^= cipher.k[$subkey_size - 2]; - d1 ^= cipher.k[$subkey_size - 1]; - - BE::write_u64_into(&[d2, d1], block.get_out()); - } - decrypt: { - let b = block.get_in(); - let mut d1 = u64::from_be_bytes(b[0..8].try_into().unwrap()); - let mut d2 = u64::from_be_bytes(b[8..16].try_into().unwrap()); - - d2 ^= cipher.k[$subkey_size - 1]; - d1 ^= cipher.k[$subkey_size - 2]; - - for i in (2..$subkey_size - 2).rev().step_by(2) { - if (i - 1) % 8 == 0 { - d1 = fl(d1, cipher.k[i]); - d2 = flinv(d2, cipher.k[i - 1]); - - continue; - } - d2 ^= f(d1, cipher.k[i]); - d1 ^= f(d2, cipher.k[i - 1]); - } - - d1 ^= cipher.k[1]; - d2 ^= cipher.k[0]; - - BE::write_u64_into(&[d2, d1], block.get_out()); - } - ); - }; -} - -impl_camellia!(Camellia128, 26, U16, "Camellia-128 block cipher instance."); -impl_camellia!(Camellia192, 34, U24, "Camellia-192 block cipher instance."); -impl_camellia!(Camellia256, 34, U32, "Camellia-256 block cipher instance."); diff --git a/camellia/src/camellia128.rs b/camellia/src/camellia128.rs new file mode 100644 index 00000000..23b81ca5 --- /dev/null +++ b/camellia/src/camellia128.rs @@ -0,0 +1,35 @@ +use crate::{ + utils::{gen_subkeys26, set_ka}, + Camellia128, +}; +use cipher::{AlgorithmName, Key, KeyInit}; +use core::{fmt, marker::PhantomData}; + +impl KeyInit for Camellia128 { + fn new(key: &Key) -> Self { + let kl = ( + u64::from_be_bytes(key[0..8].try_into().unwrap()), + u64::from_be_bytes(key[8..16].try_into().unwrap()), + ); + let kr = (u64::default(), u64::default()); + + let ka = set_ka(kl, kr); + + Self { + k: gen_subkeys26(kl, ka), + _pd: PhantomData, + } + } +} + +impl fmt::Debug for Camellia128 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Camellia128 { ... }") + } +} + +impl AlgorithmName for Camellia128 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Camellia128") + } +} diff --git a/camellia/src/camellia192.rs b/camellia/src/camellia192.rs new file mode 100644 index 00000000..a842dfda --- /dev/null +++ b/camellia/src/camellia192.rs @@ -0,0 +1,37 @@ +use crate::{ + utils::{get_subkeys34, set_ka, set_kb}, + Camellia192, +}; +use cipher::{AlgorithmName, Key, KeyInit}; +use core::{fmt, marker::PhantomData}; + +impl KeyInit for Camellia192 { + fn new(key: &Key) -> Self { + let kl = ( + u64::from_be_bytes(key[0..8].try_into().unwrap()), + u64::from_be_bytes(key[8..16].try_into().unwrap()), + ); + let kr = u64::from_be_bytes(key[16..24].try_into().unwrap()); + let kr = (kr, !kr); + + let ka = set_ka(kl, kr); + let kb = set_kb(ka, kr); + + Self { + k: get_subkeys34(kl, kr, ka, kb), + _pd: PhantomData, + } + } +} + +impl fmt::Debug for Camellia192 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Camellia192 { ... }") + } +} + +impl AlgorithmName for Camellia192 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Camellia192") + } +} diff --git a/camellia/src/camellia256.rs b/camellia/src/camellia256.rs new file mode 100644 index 00000000..9289683e --- /dev/null +++ b/camellia/src/camellia256.rs @@ -0,0 +1,39 @@ +use crate::{ + utils::{get_subkeys34, set_ka, set_kb}, + Camellia256, +}; +use cipher::{AlgorithmName, Key, KeyInit}; +use core::{fmt, marker::PhantomData}; + +impl KeyInit for Camellia256 { + fn new(key: &Key) -> Self { + let kl = ( + u64::from_be_bytes(key[0..8].try_into().unwrap()), + u64::from_be_bytes(key[8..16].try_into().unwrap()), + ); + let kr = ( + u64::from_be_bytes(key[16..24].try_into().unwrap()), + u64::from_be_bytes(key[24..32].try_into().unwrap()), + ); + + let ka = set_ka(kl, kr); + let kb = set_kb(ka, kr); + + Self { + k: get_subkeys34(kl, kr, ka, kb), + _pd: PhantomData, + } + } +} + +impl fmt::Debug for Camellia256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Camellia256 { ... }") + } +} + +impl AlgorithmName for Camellia256 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Camellia256") + } +} diff --git a/camellia/src/lib.rs b/camellia/src/lib.rs index 83bec0f5..b56ae7a4 100644 --- a/camellia/src/lib.rs +++ b/camellia/src/lib.rs @@ -10,8 +10,11 @@ //! //! # Examples //! ``` -//! use camellia::cipher::array::Array; -//! use camellia::cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit}; +//! use camellia::cipher::{ +//! array::Array, +//! block::{BlockCipherDecrypt, BlockCipherEncrypt}, +//! KeyInit, +//! }; //! use camellia::Camellia128; //! //! let key = Array::from([0_u8; 16]); @@ -39,12 +42,146 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] +use core::marker::PhantomData; + pub use cipher; -mod camellia; +use cipher::{ + array::ArraySize, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U16, U24, U32}, + inout::InOut, + Block, BlockSizeUser, KeySizeUser, ParBlocksSizeUser, +}; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +mod camellia128; +mod camellia192; +mod camellia256; mod consts; +mod utils; + +use utils::{f, fl, flinv}; + +/// Generic implementation of the Camellia block cipher. +/// +/// This type can be initialized only with 3 combinations of `KeySize` and `RK`: +/// - Camellia-128: U16, 26 +/// - Camellia-192: U24, 34 +/// - Camellia-256: U32, 34 +#[derive(Clone)] +pub struct Camellia { + k: [u64; RK], + _pd: PhantomData, +} + +/// Camellia-128 block cipher instance. +pub type Camellia128 = Camellia; +/// Camellia-192 block cipher instance. +pub type Camellia192 = Camellia; +/// Camellia-256 block cipher instance. +pub type Camellia256 = Camellia; + +impl KeySizeUser for Camellia { + type KeySize = KeySize; +} + +impl BlockSizeUser for Camellia { + type BlockSize = U16; +} + +impl ParBlocksSizeUser for Camellia { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for Camellia { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for Camellia { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let b = block.get_in(); + let mut d1 = u64::from_be_bytes(b[0..8].try_into().unwrap()); + let mut d2 = u64::from_be_bytes(b[8..16].try_into().unwrap()); + + d1 ^= self.k[0]; + d2 ^= self.k[1]; + + for i in (2..RK - 2).step_by(2) { + if i % 8 == 0 { + d1 = fl(d1, self.k[i]); + d2 = flinv(d2, self.k[i + 1]); + + continue; + } + d2 ^= f(d1, self.k[i]); + d1 ^= f(d2, self.k[i + 1]); + } + + d2 ^= self.k[RK - 2]; + d1 ^= self.k[RK - 1]; + + let (b1, b2) = block.get_out().split_at_mut(8); + b1.copy_from_slice(&d2.to_be_bytes()); + b2.copy_from_slice(&d1.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for Camellia { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for Camellia { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let b = block.get_in(); + let mut d1 = u64::from_be_bytes(b[0..8].try_into().unwrap()); + let mut d2 = u64::from_be_bytes(b[8..16].try_into().unwrap()); + + d2 ^= self.k[RK - 1]; + d1 ^= self.k[RK - 2]; + + for i in (2..RK - 2).rev().step_by(2) { + if (i - 1) % 8 == 0 { + d1 = fl(d1, self.k[i]); + d2 = flinv(d2, self.k[i - 1]); + + continue; + } + d2 ^= f(d1, self.k[i]); + d1 ^= f(d2, self.k[i - 1]); + } + + d1 ^= self.k[1]; + d2 ^= self.k[0]; + + let (b1, b2) = block.get_out().split_at_mut(8); + b1.copy_from_slice(&d2.to_be_bytes()); + b2.copy_from_slice(&d1.to_be_bytes()); + } +} + +impl Drop for Camellia { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + self.k.zeroize(); + } +} -pub use crate::camellia::{Camellia128, Camellia192, Camellia256}; +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for Camellia {} diff --git a/camellia/src/utils.rs b/camellia/src/utils.rs new file mode 100644 index 00000000..13eba95f --- /dev/null +++ b/camellia/src/utils.rs @@ -0,0 +1,178 @@ +use crate::consts::{SBOXES, SIGMAS}; + +/// F-function of component of Camellia defined in RFC 3713. +pub(crate) fn f(input: u64, key: u64) -> u64 { + let x = (input ^ key).to_be_bytes(); + + let z1 = 0x0101_0100_0100_0001 * u64::from(SBOXES[0][usize::from(x[0])]); + let z2 = 0x0001_0101_0101_0000 * u64::from(SBOXES[1][usize::from(x[1])]); + let z3 = 0x0100_0101_0001_0100 * u64::from(SBOXES[2][usize::from(x[2])]); + let z4 = 0x0101_0001_0000_0101 * u64::from(SBOXES[3][usize::from(x[3])]); + let z5 = 0x0001_0101_0001_0101 * u64::from(SBOXES[1][usize::from(x[4])]); + let z6 = 0x0100_0101_0100_0101 * u64::from(SBOXES[2][usize::from(x[5])]); + let z7 = 0x0101_0001_0101_0001 * u64::from(SBOXES[3][usize::from(x[6])]); + let z8 = 0x0101_0100_0101_0100 * u64::from(SBOXES[0][usize::from(x[7])]); + + z1 ^ z2 ^ z3 ^ z4 ^ z5 ^ z6 ^ z7 ^ z8 +} + +/// FL-function of component of Camellia defined in RFC 3713. +pub(crate) fn fl(input: u64, key: u64) -> u64 { + let mut x1 = u32::try_from(input >> 32).unwrap(); + let mut x2 = u32::try_from(input & 0xffff_ffff).unwrap(); + + let k1 = u32::try_from(key >> 32).unwrap(); + let k2 = u32::try_from(key & 0xffff_ffff).unwrap(); + + x2 ^= (x1 & k1).rotate_left(1); + x1 ^= x2 | k2; + + (u64::from(x1) << 32) | u64::from(x2) +} + +/// FLINV-function of component of Camellia defined in RFC 3713. +pub(crate) fn flinv(input: u64, key: u64) -> u64 { + let mut y1 = u32::try_from(input >> 32).unwrap(); + let mut y2 = u32::try_from(input & 0xffff_ffff).unwrap(); + + let k1 = u32::try_from(key >> 32).unwrap(); + let k2 = u32::try_from(key & 0xffff_ffff).unwrap(); + + y1 ^= y2 | k2; + y2 ^= (y1 & k1).rotate_left(1); + + (u64::from(y1) << 32) | u64::from(y2) +} + +pub(crate) fn set_ka(kl: (u64, u64), kr: (u64, u64)) -> (u64, u64) { + let mut d1 = kl.0 ^ kr.0; + let mut d2 = kl.1 ^ kr.1; + d2 ^= f(d1, SIGMAS[0]); + d1 ^= f(d2, SIGMAS[1]); + d1 ^= kl.0; + d2 ^= kl.1; + d2 ^= f(d1, SIGMAS[2]); + d1 ^= f(d2, SIGMAS[3]); + + (d1, d2) +} + +pub(crate) fn set_kb(ka: (u64, u64), kr: (u64, u64)) -> (u64, u64) { + let mut d1 = ka.0 ^ kr.0; + let mut d2 = ka.1 ^ kr.1; + d2 ^= f(d1, SIGMAS[4]); + d1 ^= f(d2, SIGMAS[5]); + + (d1, d2) +} + +/// Performs rotate left and taking the higher-half of it. +fn rotate_left_high(val: (u64, u64), mut shift: u8) -> u64 { + if shift >= 64 { + shift -= 64; + } + + (val.0 << shift) | (val.1 >> (64 - shift)) +} + +/// Performs rotate left and taking the lower-half of it. +fn rotate_left_low(val: (u64, u64), mut shift: u8) -> u64 { + if shift >= 64 { + shift -= 64; + } + + (val.0 >> (64 - shift)) | (val.1 << shift) +} + +pub(crate) fn gen_subkeys26(kl: (u64, u64), ka: (u64, u64)) -> [u64; 26] { + let mut k = [0; 26]; + + k[0] = kl.0; + k[1] = kl.1; + + k[2] = ka.0; + k[3] = ka.1; + k[4] = rotate_left_high(kl, 15); + k[5] = rotate_left_low(kl, 15); + k[6] = rotate_left_high(ka, 15); + k[7] = rotate_left_low(ka, 15); + + k[8] = rotate_left_high(ka, 30); + k[9] = rotate_left_low(ka, 30); + + k[10] = rotate_left_high(kl, 45); + k[11] = rotate_left_low(kl, 45); + k[12] = rotate_left_high(ka, 45); + k[13] = rotate_left_low(kl, 60); + k[14] = rotate_left_high(ka, 60); + k[15] = rotate_left_low(ka, 60); + + k[16] = rotate_left_low(kl, 77); + k[17] = rotate_left_high(kl, 77); + + k[18] = rotate_left_low(kl, 94); + k[19] = rotate_left_high(kl, 94); + k[20] = rotate_left_low(ka, 94); + k[21] = rotate_left_high(ka, 94); + k[22] = rotate_left_low(kl, 111); + k[23] = rotate_left_high(kl, 111); + + k[24] = rotate_left_low(ka, 111); + k[25] = rotate_left_high(ka, 111); + + k +} + +pub(crate) fn get_subkeys34( + kl: (u64, u64), + kr: (u64, u64), + ka: (u64, u64), + kb: (u64, u64), +) -> [u64; 34] { + let mut k = [u64::default(); 34]; + + k[0] = kl.0; + k[1] = kl.1; + + k[2] = kb.0; + k[3] = kb.1; + k[4] = rotate_left_high(kr, 15); + k[5] = rotate_left_low(kr, 15); + k[6] = rotate_left_high(ka, 15); + k[7] = rotate_left_low(ka, 15); + + k[8] = rotate_left_high(kr, 30); + k[9] = rotate_left_low(kr, 30); + + k[10] = rotate_left_high(kb, 30); + k[11] = rotate_left_low(kb, 30); + k[12] = rotate_left_high(kl, 45); + k[13] = rotate_left_low(kl, 45); + k[14] = rotate_left_high(ka, 45); + k[15] = rotate_left_low(ka, 45); + + k[16] = rotate_left_high(kl, 60); + k[17] = rotate_left_low(kl, 60); + + k[18] = rotate_left_high(kr, 60); + k[19] = rotate_left_low(kr, 60); + k[20] = rotate_left_high(kb, 60); + k[21] = rotate_left_low(kb, 60); + k[22] = rotate_left_low(kl, 77); + k[23] = rotate_left_high(kl, 77); + + k[24] = rotate_left_low(ka, 77); + k[25] = rotate_left_high(ka, 77); + + k[26] = rotate_left_low(kr, 94); + k[27] = rotate_left_high(kr, 94); + k[28] = rotate_left_low(ka, 94); + k[29] = rotate_left_high(ka, 94); + k[30] = rotate_left_low(kl, 111); + k[31] = rotate_left_high(kl, 111); + + k[32] = rotate_left_low(kb, 111); + k[33] = rotate_left_high(kb, 111); + + k +} diff --git a/cast5/src/lib.rs b/cast5/src/lib.rs index 575f0d33..edb0a660 100644 --- a/cast5/src/lib.rs +++ b/cast5/src/lib.rs @@ -10,8 +10,11 @@ //! //! # Examples //! ``` -//! use cast5::cipher::array::Array; -//! use cast5::cipher::{Key, Block, BlockCipherEncrypt, BlockCipherDecrypt, KeyInit}; +//! use cast5::cipher::{ +//! array::Array, +//! block::{BlockCipherDecrypt, BlockCipherEncrypt}, +//! KeyInit, +//! }; //! use cast5::Cast5; //! //! let key = Array::from([0u8; 16]); @@ -36,7 +39,7 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] pub use cipher; @@ -45,8 +48,13 @@ mod consts; mod schedule; use cipher::{ - consts::{U16, U8}, - AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U16, U8}, + AlgorithmName, Block, BlockSizeUser, InOut, InvalidLength, Key, KeyInit, KeySizeUser, + ParBlocksSizeUser, }; use core::fmt; @@ -129,8 +137,6 @@ macro_rules! f3 { }}; } -impl BlockCipher for Cast5 {} - impl KeySizeUser for Cast5 { type KeySize = U16; } @@ -159,37 +165,26 @@ impl KeyInit for Cast5 { } } -impl fmt::Debug for Cast5 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("Cast5 { ... }") - } +impl BlockSizeUser for Cast5 { + type BlockSize = U8; } -impl AlgorithmName for Cast5 { - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("Cast5") - } +impl ParBlocksSizeUser for Cast5 { + type ParBlocksSize = U1; } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Drop for Cast5 { - fn drop(&mut self) { - self.masking.zeroize(); - self.rotate.zeroize(); - self.small_key.zeroize(); +impl BlockCipherEncrypt for Cast5 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) } } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl ZeroizeOnDrop for Cast5 {} - -cipher::impl_simple_block_encdec!( - Cast5, U8, cipher, block, - encrypt: { - let masking = cipher.masking; - let rotate = cipher.rotate; +impl BlockCipherEncBackend for Cast5 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let masking = self.masking; + let rotate = self.rotate; // (L0,R0) <-- (m1...m64). (Split the plaintext into left and // right 32-bit halves L0 = m1...m32 and R0 = m33...m64.) @@ -218,7 +213,7 @@ cipher::impl_simple_block_encdec!( let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10])); let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11])); - let (l, r) = if cipher.small_key { + let (l, r) = if self.small_key { (l, r) } else { // Rounds 13..16 are only executed for keys > 80 bits. @@ -234,15 +229,26 @@ cipher::impl_simple_block_encdec!( block[0..4].copy_from_slice(&r.to_be_bytes()); block[4..8].copy_from_slice(&l.to_be_bytes()); } - decrypt: { - let masking = cipher.masking; - let rotate = cipher.rotate; +} + +impl BlockCipherDecrypt for Cast5 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for Cast5 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let masking = self.masking; + let rotate = self.rotate; let b = block.get_in(); let l = u32::from_be_bytes(b[0..4].try_into().unwrap()); let r = u32::from_be_bytes(b[4..8].try_into().unwrap()); - let (l, r) = if cipher.small_key { + let (l, r) = if self.small_key { (l, r) } else { let (l, r) = (r, l ^ f1!(r, masking[15], rotate[15])); @@ -268,4 +274,30 @@ cipher::impl_simple_block_encdec!( block[0..4].copy_from_slice(&r.to_be_bytes()); block[4..8].copy_from_slice(&l.to_be_bytes()); } -); +} + +impl fmt::Debug for Cast5 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cast5 { ... }") + } +} + +impl AlgorithmName for Cast5 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cast5") + } +} + +impl Drop for Cast5 { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + { + self.masking.zeroize(); + self.rotate.zeroize(); + self.small_key.zeroize(); + } + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for Cast5 {} diff --git a/cast5/tests/mod.rs b/cast5/tests/mod.rs index 9da6622d..b828e5fb 100644 --- a/cast5/tests/mod.rs +++ b/cast5/tests/mod.rs @@ -1,5 +1,9 @@ use cast5::Cast5; -use cipher::{array::Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit}; +use cipher::{ + array::Array, + block::{BlockCipherDecrypt, BlockCipherEncrypt}, + KeyInit, +}; use hex_literal::hex; /// Test vectors from RFC 2144 Appendix B.1 diff --git a/cast6/src/lib.rs b/cast6/src/lib.rs index e6d2c89a..13b72036 100644 --- a/cast6/src/lib.rs +++ b/cast6/src/lib.rs @@ -10,8 +10,11 @@ //! //! # Examples //! ``` -//! use cast6::cipher::array::Array; -//! use cast6::cipher::{Key, Block, BlockCipherEncrypt, BlockCipherDecrypt, KeyInit}; +//! use cast6::cipher::{ +//! array::Array, +//! block::{BlockCipherDecrypt, BlockCipherEncrypt}, +//! KeyInit, +//! }; //! use cast6::Cast6; //! //! let key = Array::from([0u8; 32]); @@ -36,7 +39,7 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] pub use cipher; @@ -44,8 +47,13 @@ pub use cipher; mod consts; use cipher::{ - consts::{U16, U32}, - AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U16, U32}, + AlgorithmName, Block, BlockSizeUser, InOut, InvalidLength, Key, KeyInit, KeySizeUser, + ParBlocksSizeUser, }; use core::fmt; @@ -172,8 +180,6 @@ fn forward_octave(kappa: &mut [u32; 8], m: &[u32], r: &[u8]) { *h ^= f2!(*a, m[7], r[7]); } -impl BlockCipher for Cast6 {} - impl KeySizeUser for Cast6 { type KeySize = U32; } @@ -201,36 +207,26 @@ impl KeyInit for Cast6 { } } -impl fmt::Debug for Cast6 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("Cast6 { ... }") - } +impl BlockSizeUser for Cast6 { + type BlockSize = U16; } -impl AlgorithmName for Cast6 { - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("Cast6") - } +impl ParBlocksSizeUser for Cast6 { + type ParBlocksSize = U1; } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Drop for Cast6 { - fn drop(&mut self) { - self.masking.zeroize(); - self.rotate.zeroize(); +impl BlockCipherEncrypt for Cast6 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) } } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl ZeroizeOnDrop for Cast6 {} - -cipher::impl_simple_block_encdec!( - Cast6, U16, cipher, block, - encrypt: { - let masking = &cipher.masking; - let rotate = &cipher.rotate; +impl BlockCipherEncBackend for Cast6 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let masking = &self.masking; + let rotate = &self.rotate; // Let BETA = (ABCD) be a 128-bit block where A, B, C and D are each // 32 bits in length. @@ -258,9 +254,20 @@ cipher::impl_simple_block_encdec!( // 128bits of ciphertext = BETA *block.get_out() = to_u8s::<16>(&beta).into(); } - decrypt: { - let masking = &cipher.masking; - let rotate = &cipher.rotate; +} + +impl BlockCipherDecrypt for Cast6 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for Cast6 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let masking = &self.masking; + let rotate = &self.rotate; let mut beta = to_u32s(block.get_in()); @@ -280,7 +287,32 @@ cipher::impl_simple_block_encdec!( *block.get_out() = to_u8s::<16>(&beta).into(); } -); +} + +impl fmt::Debug for Cast6 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cast6 { ... }") + } +} + +impl AlgorithmName for Cast6 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cast6") + } +} + +impl Drop for Cast6 { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + { + self.masking.zeroize(); + self.rotate.zeroize(); + } + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for Cast6 {} fn to_u32s(src: &[u8]) -> [u32; N] { assert_eq!(src.len(), 4 * N); diff --git a/cast6/tests/mod.rs b/cast6/tests/mod.rs index 6f7bf4d8..7232220a 100644 --- a/cast6/tests/mod.rs +++ b/cast6/tests/mod.rs @@ -1,5 +1,8 @@ use cast6::Cast6; -use cipher::{Block, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit}; +use cipher::{ + block::{BlockCipherDecrypt, BlockCipherEncrypt}, + Block, KeyInit, +}; use hex_literal::hex; /// Test vectors from RFC 2612 Appendix A diff --git a/des/src/des.rs b/des/src/des.rs index 6a748f5d..7e72c44f 100644 --- a/des/src/des.rs +++ b/des/src/des.rs @@ -2,13 +2,20 @@ #![allow(clippy::unreadable_literal)] -use cipher::{consts::U8, AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser}; +use cipher::{ + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U8}, + AlgorithmName, Block, BlockSizeUser, InOut, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, +}; use core::fmt; #[cfg(feature = "zeroize")] use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::consts::{SBOXES, SHIFTS}; +use crate::utils::{fp, gen_keys, ip, round}; /// Data Encryption Standard (DES) block cipher. #[derive(Clone)] @@ -16,157 +23,6 @@ pub struct Des { pub(crate) keys: [u64; 16], } -/// Swap bits in `a` using a delta swap -fn delta_swap(a: u64, delta: u64, mask: u64) -> u64 { - let b = (a ^ (a >> delta)) & mask; - a ^ b ^ (b << delta) -} - -/// Swap bits using the PC-1 table -fn pc1(mut key: u64) -> u64 { - key = delta_swap(key, 2, 0x3333000033330000); - key = delta_swap(key, 4, 0x0f0f0f0f00000000); - key = delta_swap(key, 8, 0x009a000a00a200a8); - key = delta_swap(key, 16, 0x00006c6c0000cccc); - key = delta_swap(key, 1, 0x1045500500550550); - key = delta_swap(key, 32, 0x00000000f0f0f5fa); - key = delta_swap(key, 8, 0x00550055006a00aa); - key = delta_swap(key, 2, 0x0000333330000300); - key & 0xFFFFFFFFFFFFFF00 -} - -/// Swap bits using the PC-2 table -fn pc2(key: u64) -> u64 { - let key = key.rotate_left(61); - let b1 = (key & 0x0021000002000000) >> 7; - let b2 = (key & 0x0008020010080000) << 1; - let b3 = key & 0x0002200000000000; - let b4 = (key & 0x0000000000100020) << 19; - let b5 = (key.rotate_left(54) & 0x0005312400000011).wrapping_mul(0x0000000094200201) - & 0xea40100880000000; - let b6 = (key.rotate_left(7) & 0x0022110000012001).wrapping_mul(0x0001000000610006) - & 0x1185004400000000; - let b7 = (key.rotate_left(6) & 0x0000520040200002).wrapping_mul(0x00000080000000c1) - & 0x0028811000200000; - let b8 = (key & 0x01000004c0011100).wrapping_mul(0x0000000000004284) & 0x0400082244400000; - let b9 = (key.rotate_left(60) & 0x0000000000820280).wrapping_mul(0x0000000000089001) - & 0x0000000110880000; - let b10 = (key.rotate_left(49) & 0x0000000000024084).wrapping_mul(0x0000000002040005) - & 0x000000000a030000; - b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 -} - -/// Swap bits using the reverse FP table -fn fp(mut message: u64) -> u64 { - message = delta_swap(message, 24, 0x000000FF000000FF); - message = delta_swap(message, 24, 0x00000000FF00FF00); - message = delta_swap(message, 36, 0x000000000F0F0F0F); - message = delta_swap(message, 18, 0x0000333300003333); - delta_swap(message, 9, 0x0055005500550055) -} - -/// Swap bits using the IP table -fn ip(mut message: u64) -> u64 { - message = delta_swap(message, 9, 0x0055005500550055); - message = delta_swap(message, 18, 0x0000333300003333); - message = delta_swap(message, 36, 0x000000000F0F0F0F); - message = delta_swap(message, 24, 0x00000000FF00FF00); - delta_swap(message, 24, 0x000000FF000000FF) -} - -/// Swap bits using the E table -fn e(block: u64) -> u64 { - const BLOCK_LEN: usize = 32; - const RESULT_LEN: usize = 48; - - let b1 = (block << (BLOCK_LEN - 1)) & 0x8000000000000000; - let b2 = (block >> 1) & 0x7C00000000000000; - let b3 = (block >> 3) & 0x03F0000000000000; - let b4 = (block >> 5) & 0x000FC00000000000; - let b5 = (block >> 7) & 0x00003F0000000000; - let b6 = (block >> 9) & 0x000000FC00000000; - let b7 = (block >> 11) & 0x00000003F0000000; - let b8 = (block >> 13) & 0x000000000FC00000; - let b9 = (block >> 15) & 0x00000000003E0000; - let b10 = (block >> (RESULT_LEN - 1)) & 0x0000000000010000; - b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 -} - -/// Swap bits using the P table -fn p(block: u64) -> u64 { - let block = block.rotate_left(44); - let b1 = (block & 0x0000000000200000) << 32; - let b2 = (block & 0x0000000000480000) << 13; - let b3 = (block & 0x0000088000000000) << 12; - let b4 = (block & 0x0000002020120000) << 25; - let b5 = (block & 0x0000000442000000) << 14; - let b6 = (block & 0x0000000001800000) << 37; - let b7 = (block & 0x0000000004000000) << 24; - let b8 = (block & 0x0000020280015000).wrapping_mul(0x0000020080800083) & 0x02000a6400000000; - let b9 = (block.rotate_left(29) & 0x01001400000000aa).wrapping_mul(0x0000210210008081) - & 0x0902c01200000000; - let b10 = (block & 0x0000000910040000).wrapping_mul(0x0000000c04000020) & 0x8410010000000000; - b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 -} - -/// Generate the 16 subkeys -pub(crate) fn gen_keys(key: u64) -> [u64; 16] { - let mut keys: [u64; 16] = [0; 16]; - let key = pc1(key); - - // The most significant bit is bit zero, and there are only 56 bits in - // the key after applying PC1, so we need to remove the eight least - // significant bits from the key. - let key = key >> 8; - - let mut c = key >> 28; - let mut d = key & 0x0FFFFFFF; - for i in 0..16 { - c = rotate(c, SHIFTS[i]); - d = rotate(d, SHIFTS[i]); - - // We need the `<< 8` because the most significant bit is bit zero, - // so we need to shift our 56 bit value 8 bits to the left. - keys[i] = pc2(((c << 28) | d) << 8); - } - - keys -} - -/// Performs a left rotate on a 28 bit number -fn rotate(mut val: u64, shift: u8) -> u64 { - let top_bits = val >> (28 - shift); - val <<= shift; - - (val | top_bits) & 0x0FFFFFFF -} - -fn round(input: u64, key: u64) -> u64 { - let l = input & (0xFFFF_FFFF << 32); - let r = input << 32; - - r | ((f(r, key) ^ l) >> 32) -} - -fn f(input: u64, key: u64) -> u64 { - let mut val = e(input); - val ^= key; - val = apply_sboxes(val); - p(val) -} - -/// Applies all eight sboxes to the input -fn apply_sboxes(input: u64) -> u64 { - let mut output: u64 = 0; - - for (i, sbox) in SBOXES.iter().enumerate() { - let val = (input >> (58 - (i * 6))) & 0x3F; - output |= u64::from(sbox[val as usize]) << (60 - (i * 4)); - } - - output -} - impl Des { pub(crate) fn encrypt(&self, mut data: u64) -> u64 { data = ip(data); @@ -185,8 +41,6 @@ impl Des { } } -impl BlockCipher for Des {} - impl KeySizeUser for Des { type KeySize = U8; } @@ -194,11 +48,51 @@ impl KeySizeUser for Des { impl KeyInit for Des { #[inline] fn new(key: &Key) -> Self { - let keys = gen_keys(u64::from_be_bytes(key.clone().into())); + let keys = gen_keys(u64::from_be_bytes(key.0)); Self { keys } } } +impl BlockSizeUser for Des { + type BlockSize = U8; +} + +impl ParBlocksSizeUser for Des { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for Des { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for Des { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for Des { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for Des { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + impl fmt::Debug for Des { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Des { ... }") @@ -211,28 +105,12 @@ impl AlgorithmName for Des { } } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl Drop for Des { fn drop(&mut self) { + #[cfg(feature = "zeroize")] self.keys.zeroize(); } } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for Des {} - -cipher::impl_simple_block_encdec!( - Des, U8, cipher, block, - encrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.encrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } - decrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.decrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } -); diff --git a/des/src/lib.rs b/des/src/lib.rs index 323406e9..7dc04377 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -18,15 +18,15 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] -#![allow(clippy::clone_on_copy)] // TODO: remove on migration to const generics pub use cipher; mod consts; mod des; mod tdes; +mod utils; pub use crate::des::Des; pub use crate::tdes::{TdesEde2, TdesEde3, TdesEee2, TdesEee3}; diff --git a/des/src/tdes.rs b/des/src/tdes.rs index ad210824..b3be46b6 100644 --- a/des/src/tdes.rs +++ b/des/src/tdes.rs @@ -1,9 +1,13 @@ //! Triple DES (3DES) block ciphers. -use crate::des::{gen_keys, Des}; +use crate::{utils::gen_keys, Des}; use cipher::{ - consts::{U16, U24, U8}, - AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts::{U1, U16, U24, U8}, + AlgorithmName, Block, BlockSizeUser, InOut, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, }; use core::fmt; @@ -18,8 +22,6 @@ pub struct TdesEde3 { d3: Des, } -impl BlockCipher for TdesEde3 {} - impl KeySizeUser for TdesEde3 { type KeySize = U24; } @@ -37,6 +39,50 @@ impl KeyInit for TdesEde3 { } } +impl BlockSizeUser for TdesEde3 { + type BlockSize = U8; +} + +impl ParBlocksSizeUser for TdesEde3 { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for TdesEde3 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for TdesEde3 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d1.encrypt(data); + data = self.d2.decrypt(data); + data = self.d3.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for TdesEde3 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for TdesEde3 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d3.decrypt(data); + data = self.d2.encrypt(data); + data = self.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + impl fmt::Debug for TdesEde3 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("TdesEee3 { ... }") @@ -50,27 +96,8 @@ impl AlgorithmName for TdesEde3 { } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for TdesEde3 {} -cipher::impl_simple_block_encdec!( - TdesEde3, U8, cipher, block, - encrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d1.encrypt(data); - data = cipher.d2.decrypt(data); - data = cipher.d3.encrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } - decrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d3.decrypt(data); - data = cipher.d2.encrypt(data); - data = cipher.d1.decrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } -); - /// Triple DES (3DES) block cipher. #[derive(Clone)] pub struct TdesEee3 { @@ -79,8 +106,6 @@ pub struct TdesEee3 { d3: Des, } -impl BlockCipher for TdesEee3 {} - impl KeySizeUser for TdesEee3 { type KeySize = U24; } @@ -98,6 +123,50 @@ impl KeyInit for TdesEee3 { } } +impl BlockSizeUser for TdesEee3 { + type BlockSize = U8; +} + +impl ParBlocksSizeUser for TdesEee3 { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for TdesEee3 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for TdesEee3 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d1.encrypt(data); + data = self.d2.encrypt(data); + data = self.d3.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for TdesEee3 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for TdesEee3 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d3.decrypt(data); + data = self.d2.decrypt(data); + data = self.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + impl fmt::Debug for TdesEee3 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("TdesEee3 { ... }") @@ -111,27 +180,8 @@ impl AlgorithmName for TdesEee3 { } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for TdesEee3 {} -cipher::impl_simple_block_encdec!( - TdesEee3, U8, cipher, block, - encrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d1.encrypt(data); - data = cipher.d2.encrypt(data); - data = cipher.d3.encrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } - decrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d3.decrypt(data); - data = cipher.d2.decrypt(data); - data = cipher.d1.decrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } -); - /// Triple DES (3DES) block cipher. #[derive(Clone)] pub struct TdesEde2 { @@ -139,8 +189,6 @@ pub struct TdesEde2 { d2: Des, } -impl BlockCipher for TdesEde2 {} - impl KeySizeUser for TdesEde2 { type KeySize = U16; } @@ -156,6 +204,50 @@ impl KeyInit for TdesEde2 { } } +impl BlockSizeUser for TdesEde2 { + type BlockSize = U8; +} + +impl ParBlocksSizeUser for TdesEde2 { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for TdesEde2 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for TdesEde2 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d1.encrypt(data); + data = self.d2.decrypt(data); + data = self.d1.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for TdesEde2 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for TdesEde2 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d1.decrypt(data); + data = self.d2.encrypt(data); + data = self.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + impl fmt::Debug for TdesEde2 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("TdesEde2 { ... }") @@ -169,27 +261,8 @@ impl AlgorithmName for TdesEde2 { } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for TdesEde2 {} -cipher::impl_simple_block_encdec!( - TdesEde2, U8, cipher, block, - encrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d1.encrypt(data); - data = cipher.d2.decrypt(data); - data = cipher.d1.encrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } - decrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d1.decrypt(data); - data = cipher.d2.encrypt(data); - data = cipher.d1.decrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } -); - /// Triple DES (3DES) block cipher. #[derive(Clone)] pub struct TdesEee2 { @@ -197,8 +270,6 @@ pub struct TdesEee2 { d2: Des, } -impl BlockCipher for TdesEee2 {} - impl KeySizeUser for TdesEee2 { type KeySize = U16; } @@ -214,6 +285,50 @@ impl KeyInit for TdesEee2 { } } +impl BlockSizeUser for TdesEee2 { + type BlockSize = U8; +} + +impl ParBlocksSizeUser for TdesEee2 { + type ParBlocksSize = U1; +} + +impl BlockCipherEncrypt for TdesEee2 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherEncBackend for TdesEee2 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d1.encrypt(data); + data = self.d2.encrypt(data); + data = self.d1.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for TdesEee2 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for TdesEee2 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = self.d1.decrypt(data); + data = self.d2.decrypt(data); + data = self.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +} + impl fmt::Debug for TdesEee2 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("TdesEee2 { ... }") @@ -227,23 +342,4 @@ impl AlgorithmName for TdesEee2 { } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for TdesEee2 {} - -cipher::impl_simple_block_encdec!( - TdesEee2, U8, cipher, block, - encrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d1.encrypt(data); - data = cipher.d2.encrypt(data); - data = cipher.d1.encrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } - decrypt: { - let mut data = u64::from_be_bytes(block.clone_in().into()); - data = cipher.d1.decrypt(data); - data = cipher.d2.decrypt(data); - data = cipher.d1.decrypt(data); - block.get_out().copy_from_slice(&data.to_be_bytes()); - } -); diff --git a/des/src/utils.rs b/des/src/utils.rs new file mode 100644 index 00000000..d2782245 --- /dev/null +++ b/des/src/utils.rs @@ -0,0 +1,152 @@ +use crate::consts::{SBOXES, SHIFTS}; + +/// Swap bits in `a` using a delta swap +fn delta_swap(a: u64, delta: u64, mask: u64) -> u64 { + let b = (a ^ (a >> delta)) & mask; + a ^ b ^ (b << delta) +} + +/// Swap bits using the PC-1 table +fn pc1(mut key: u64) -> u64 { + key = delta_swap(key, 2, 0x3333000033330000); + key = delta_swap(key, 4, 0x0f0f0f0f00000000); + key = delta_swap(key, 8, 0x009a000a00a200a8); + key = delta_swap(key, 16, 0x00006c6c0000cccc); + key = delta_swap(key, 1, 0x1045500500550550); + key = delta_swap(key, 32, 0x00000000f0f0f5fa); + key = delta_swap(key, 8, 0x00550055006a00aa); + key = delta_swap(key, 2, 0x0000333330000300); + key & 0xFFFFFFFFFFFFFF00 +} + +/// Swap bits using the PC-2 table +fn pc2(key: u64) -> u64 { + let key = key.rotate_left(61); + let b1 = (key & 0x0021000002000000) >> 7; + let b2 = (key & 0x0008020010080000) << 1; + let b3 = key & 0x0002200000000000; + let b4 = (key & 0x0000000000100020) << 19; + let b5 = (key.rotate_left(54) & 0x0005312400000011).wrapping_mul(0x0000000094200201) + & 0xea40100880000000; + let b6 = (key.rotate_left(7) & 0x0022110000012001).wrapping_mul(0x0001000000610006) + & 0x1185004400000000; + let b7 = (key.rotate_left(6) & 0x0000520040200002).wrapping_mul(0x00000080000000c1) + & 0x0028811000200000; + let b8 = (key & 0x01000004c0011100).wrapping_mul(0x0000000000004284) & 0x0400082244400000; + let b9 = (key.rotate_left(60) & 0x0000000000820280).wrapping_mul(0x0000000000089001) + & 0x0000000110880000; + let b10 = (key.rotate_left(49) & 0x0000000000024084).wrapping_mul(0x0000000002040005) + & 0x000000000a030000; + b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 +} + +/// Swap bits using the reverse FP table +pub(crate) fn fp(mut message: u64) -> u64 { + message = delta_swap(message, 24, 0x000000FF000000FF); + message = delta_swap(message, 24, 0x00000000FF00FF00); + message = delta_swap(message, 36, 0x000000000F0F0F0F); + message = delta_swap(message, 18, 0x0000333300003333); + delta_swap(message, 9, 0x0055005500550055) +} + +/// Swap bits using the IP table +pub(crate) fn ip(mut message: u64) -> u64 { + message = delta_swap(message, 9, 0x0055005500550055); + message = delta_swap(message, 18, 0x0000333300003333); + message = delta_swap(message, 36, 0x000000000F0F0F0F); + message = delta_swap(message, 24, 0x00000000FF00FF00); + delta_swap(message, 24, 0x000000FF000000FF) +} + +/// Swap bits using the E table +fn e(block: u64) -> u64 { + const BLOCK_LEN: usize = 32; + const RESULT_LEN: usize = 48; + + let b1 = (block << (BLOCK_LEN - 1)) & 0x8000000000000000; + let b2 = (block >> 1) & 0x7C00000000000000; + let b3 = (block >> 3) & 0x03F0000000000000; + let b4 = (block >> 5) & 0x000FC00000000000; + let b5 = (block >> 7) & 0x00003F0000000000; + let b6 = (block >> 9) & 0x000000FC00000000; + let b7 = (block >> 11) & 0x00000003F0000000; + let b8 = (block >> 13) & 0x000000000FC00000; + let b9 = (block >> 15) & 0x00000000003E0000; + let b10 = (block >> (RESULT_LEN - 1)) & 0x0000000000010000; + b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 +} + +/// Swap bits using the P table +fn p(block: u64) -> u64 { + let block = block.rotate_left(44); + let b1 = (block & 0x0000000000200000) << 32; + let b2 = (block & 0x0000000000480000) << 13; + let b3 = (block & 0x0000088000000000) << 12; + let b4 = (block & 0x0000002020120000) << 25; + let b5 = (block & 0x0000000442000000) << 14; + let b6 = (block & 0x0000000001800000) << 37; + let b7 = (block & 0x0000000004000000) << 24; + let b8 = (block & 0x0000020280015000).wrapping_mul(0x0000020080800083) & 0x02000a6400000000; + let b9 = (block.rotate_left(29) & 0x01001400000000aa).wrapping_mul(0x0000210210008081) + & 0x0902c01200000000; + let b10 = (block & 0x0000000910040000).wrapping_mul(0x0000000c04000020) & 0x8410010000000000; + b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 +} + +/// Generate the 16 subkeys +pub(crate) fn gen_keys(key: u64) -> [u64; 16] { + let mut keys: [u64; 16] = [0; 16]; + let key = pc1(key); + + // The most significant bit is bit zero, and there are only 56 bits in + // the key after applying PC1, so we need to remove the eight least + // significant bits from the key. + let key = key >> 8; + + let mut c = key >> 28; + let mut d = key & 0x0FFFFFFF; + for i in 0..16 { + c = rotate(c, SHIFTS[i]); + d = rotate(d, SHIFTS[i]); + + // We need the `<< 8` because the most significant bit is bit zero, + // so we need to shift our 56 bit value 8 bits to the left. + keys[i] = pc2(((c << 28) | d) << 8); + } + + keys +} + +/// Performs a left rotate on a 28 bit number +fn rotate(mut val: u64, shift: u8) -> u64 { + let top_bits = val >> (28 - shift); + val <<= shift; + + (val | top_bits) & 0x0FFFFFFF +} + +pub(crate) fn round(input: u64, key: u64) -> u64 { + let l = input & (0xFFFF_FFFF << 32); + let r = input << 32; + + r | ((f(r, key) ^ l) >> 32) +} + +fn f(input: u64, key: u64) -> u64 { + let mut val = e(input); + val ^= key; + val = apply_sboxes(val); + p(val) +} + +/// Applies all eight sboxes to the input +fn apply_sboxes(input: u64) -> u64 { + let mut output: u64 = 0; + + for (i, sbox) in SBOXES.iter().enumerate() { + let val = (input >> (58 - (i * 6))) & 0x3F; + output |= u64::from(sbox[val as usize]) << (60 - (i * 4)); + } + + output +} diff --git a/magma/src/lib.rs b/magma/src/lib.rs index e0bccc1a..50d3f2da 100644 --- a/magma/src/lib.rs +++ b/magma/src/lib.rs @@ -14,7 +14,8 @@ //! use magma::Magma; //! use magma::cipher::{ //! array::Array, -//! BlockCipherEncrypt, BlockCipherDecrypt, KeyInit, +//! block::{BlockCipherEncrypt, BlockCipherDecrypt}, +//! KeyInit, //! }; //! use hex_literal::hex; //! @@ -44,14 +45,18 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" )] #![deny(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] pub use cipher; use cipher::{ - consts::{U32, U8}, - AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, + block::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, + BlockCipherEncClosure, BlockCipherEncrypt, + }, + consts, AlgorithmName, Block, BlockSizeUser, InOut, Key, KeyInit, KeySizeUser, + ParBlocksSizeUser, }; use core::{fmt, marker::PhantomData}; @@ -70,13 +75,12 @@ pub struct Gost89 { _p: PhantomData, } -impl BlockCipher for Gost89 {} - impl KeySizeUser for Gost89 { - type KeySize = U32; + type KeySize = consts::U32; } impl KeyInit for Gost89 { + #[inline] fn new(key: &Key) -> Self { let mut key_u32 = [0u32; 8]; key.chunks_exact(4) @@ -89,6 +93,68 @@ impl KeyInit for Gost89 { } } +impl BlockSizeUser for Gost89 { + type BlockSize = consts::U8; +} + +impl ParBlocksSizeUser for Gost89 { + type ParBlocksSize = consts::U1; +} + +impl BlockCipherEncBackend for Gost89 { + #[inline] + fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let b = block.get_in(); + let mut v = (to_u32(&b[0..4]), to_u32(&b[4..8])); + for _ in 0..3 { + for i in 0..8 { + v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + } + } + for i in (0..8).rev() { + v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + } + let block = block.get_out(); + block[0..4].copy_from_slice(&v.1.to_be_bytes()); + block[4..8].copy_from_slice(&v.0.to_be_bytes()); + } +} + +impl BlockCipherEncrypt for Gost89 { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + f.call(self) + } +} + +impl BlockCipherDecBackend for Gost89 { + #[inline] + fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { + let b = block.get_in(); + let mut v = (to_u32(&b[0..4]), to_u32(&b[4..8])); + + for i in 0..8 { + v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + } + + for _ in 0..3 { + for i in (0..8).rev() { + v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + } + } + let block = block.get_out(); + block[0..4].copy_from_slice(&v.1.to_be_bytes()); + block[4..8].copy_from_slice(&v.0.to_be_bytes()); + } +} + +impl BlockCipherDecrypt for Gost89 { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + f.call(self) + } +} + impl Clone for Gost89 { fn clone(&self) -> Self { Self { @@ -113,63 +179,25 @@ impl fmt::Debug for Gost89 { impl AlgorithmName for Gost89 { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { if S::NAME == "Tc26" { - f.write_str("Magma { ... }") + f.write_str("Magma") } else { f.write_str("Gost89<")?; f.write_str(S::NAME)?; - f.write_str("> { ... }") + f.write_str(">") } } } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl Drop for Gost89 { fn drop(&mut self) { + #[cfg(feature = "zeroize")] self.key.zeroize(); } } #[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] impl ZeroizeOnDrop for Gost89 {} -cipher::impl_simple_block_encdec!( - Gost89, U8, cipher, block, - encrypt: { - let b = block.get_in(); - let mut v = (to_u32(&b[0..4]), to_u32(&b[4..8])); - for _ in 0..3 { - for i in 0..8 { - v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); - } - } - for i in (0..8).rev() { - v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); - } - let block = block.get_out(); - block[0..4].copy_from_slice(&v.1.to_be_bytes()); - block[4..8].copy_from_slice(&v.0.to_be_bytes()); - } - decrypt: { - let b = block.get_in(); - let mut v = (to_u32(&b[0..4]), to_u32(&b[4..8])); - - for i in 0..8 { - v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); - } - - for _ in 0..3 { - for i in (0..8).rev() { - v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); - } - } - let block = block.get_out(); - block[0..4].copy_from_slice(&v.1.to_be_bytes()); - block[4..8].copy_from_slice(&v.0.to_be_bytes()); - } -); - /// Block cipher defined in GOST R 34.12-2015 (Magma) pub type Magma = Gost89; /// Block cipher defined in GOST 28147-89 with test S-box