diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 7e34bba0c..9fff63c52 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -36,9 +36,11 @@ pub mod block; #[cfg(feature = "dev")] mod dev; pub mod stream; +pub mod tweak; pub use block::*; pub use stream::*; +pub use tweak::*; pub use crypto_common::{ array::{self, Array}, diff --git a/cipher/src/tweak.rs b/cipher/src/tweak.rs new file mode 100644 index 000000000..ec3cb432e --- /dev/null +++ b/cipher/src/tweak.rs @@ -0,0 +1,152 @@ +//! Traits used to define functionality of [tweakable block ciphers][1]. +//! +//! [1]: https://people.eecs.berkeley.edu/~daw/papers/tweak-crypto02.pdf +use crypto_common::{ + array::{Array, ArraySize}, + Block, BlockSizeUser, +}; +use inout::InOut; + +mod ctx; +mod zero; + +pub use zero::ZeroTweak; + +/// Tweak used by a [`TweakSizeUser`] implementor. +pub type Tweak = Array::TweakSize>; + +/// Trait which contains tweak size used by the tweak cipher traits. +pub trait TweakSizeUser { + /// Size of the tweak in bytes. + type TweakSize: ArraySize; +} + +/// Encrypt-only functionality for tweakable block ciphers. +pub trait TweakBlockCipherEncrypt: BlockSizeUser + TweakSizeUser + Sized { + /// Encrypt data using backend provided to the rank-2 closure. + fn encrypt_with_backend( + &self, + f: impl TweakBlockCipherEncClosure, + ); + + /// Encrypt single `inout` block. + #[inline] + fn encrypt_block_inout(&self, tweak: &Tweak, block: InOut<'_, '_, Block>) { + self.encrypt_with_backend(ctx::BlockCtx { tweak, block }); + } + + /// Encrypt single block in-place. + #[inline] + fn encrypt_block(&self, tweak: &Tweak, block: &mut Block) { + self.encrypt_block_inout(tweak, block.into()); + } + + /// Encrypt `in_block` and write result to `out_block`. + #[inline] + fn encrypt_block_b2b( + &self, + tweak: &Tweak, + in_block: &Block, + out_block: &mut Block, + ) { + self.encrypt_block_inout(tweak, (in_block, out_block).into()); + } +} + +/// Decrypt-only functionality for tweakable block ciphers. +pub trait TweakBlockCipherDecrypt: BlockSizeUser + TweakSizeUser + Sized { + /// Decrypt data using backend provided to the rank-2 closure. + fn decrypt_with_backend( + &self, + f: impl TweakBlockCipherDecClosure, + ); + + /// Decrypt single `inout` block. + #[inline] + fn decrypt_block_inout(&self, tweak: &Tweak, block: InOut<'_, '_, Block>) { + self.decrypt_with_backend(ctx::BlockCtx { tweak, block }); + } + + /// Decrypt single block in-place. + #[inline] + fn decrypt_block(&self, tweak: &Tweak, block: &mut Block) { + self.decrypt_block_inout(tweak, block.into()); + } + + /// Decrypt `in_block` and write result to `out_block`. + #[inline] + fn decrypt_block_b2b( + &self, + tweak: &Tweak, + in_block: &Block, + out_block: &mut Block, + ) { + self.decrypt_block_inout(tweak, (in_block, out_block).into()); + } +} + +/// Trait for [`TweakBlockCipherEncBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait TweakBlockCipherEncClosure: BlockSizeUser + TweakSizeUser { + /// Execute closure with the provided block cipher backend. + fn call(self, backend: &B) + where + B: TweakBlockCipherEncBackend; +} + +/// Trait for [`TweakBlockCipherDecBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait TweakBlockCipherDecClosure: BlockSizeUser + TweakSizeUser { + /// Execute closure with the provided block cipher backend. + fn call(self, backend: &B) + where + B: TweakBlockCipherDecBackend; +} + +/// Trait implemented by block cipher mode encryption backends. +pub trait TweakBlockCipherEncBackend: BlockSizeUser + TweakSizeUser { + /// Encrypt single inout block. + fn encrypt_block_inout(&self, tweak: &Tweak, block: InOut<'_, '_, Block>); + + /// Encrypt single block in-place. + #[inline] + fn encrypt_block(&self, tweak: &Tweak, block: &mut Block) { + self.encrypt_block_inout(tweak, block.into()); + } + + /// Encrypt `in_block` and write result to `out_block`. + #[inline] + fn encrypt_block_b2b( + &self, + tweak: &Tweak, + in_block: &Block, + out_block: &mut Block, + ) { + self.encrypt_block_inout(tweak, (in_block, out_block).into()); + } +} + +/// Trait implemented by block cipher mode decryption backends. +pub trait TweakBlockCipherDecBackend: BlockSizeUser + TweakSizeUser { + /// Decrypt single inout block. + fn decrypt_block_inout(&self, tweak: &Tweak, block: InOut<'_, '_, Block>); + + /// Decrypt single block in-place. + #[inline] + fn decrypt_block(&self, tweak: &Tweak, block: &mut Block) { + self.decrypt_block_inout(tweak, block.into()); + } + + /// Decrypt `in_block` and write result to `out_block`. + #[inline] + fn decrypt_block_b2b( + &self, + tweak: &Tweak, + in_block: &Block, + out_block: &mut Block, + ) { + self.decrypt_block_inout(tweak, (in_block, out_block).into()); + } +} diff --git a/cipher/src/tweak/ctx.rs b/cipher/src/tweak/ctx.rs new file mode 100644 index 000000000..65ca6a557 --- /dev/null +++ b/cipher/src/tweak/ctx.rs @@ -0,0 +1,41 @@ +use crypto_common::{array::ArraySize, Block, BlockSizeUser, BlockSizes}; +use inout::InOut; + +use super::{ + Tweak, TweakBlockCipherDecBackend, TweakBlockCipherDecClosure, TweakBlockCipherEncBackend, + TweakBlockCipherEncClosure, TweakSizeUser, +}; + +/// Closure used in methods which operate over separate blocks. +pub(super) struct BlockCtx<'a, TS: ArraySize, BS: BlockSizes> { + pub tweak: &'a Tweak, + pub block: InOut<'a, 'a, Block>, +} + +impl BlockSizeUser for BlockCtx<'_, TS, BS> { + type BlockSize = BS; +} + +impl TweakSizeUser for BlockCtx<'_, TS, BS> { + type TweakSize = TS; +} + +impl TweakBlockCipherEncClosure for BlockCtx<'_, TS, BS> { + #[inline] + fn call(self, backend: &B) + where + B: TweakBlockCipherEncBackend, + { + backend.encrypt_block_inout(self.tweak, self.block); + } +} + +impl TweakBlockCipherDecClosure for BlockCtx<'_, TS, BS> { + #[inline] + fn call(self, backend: &B) + where + B: TweakBlockCipherDecBackend, + { + backend.decrypt_block_inout(self.tweak, self.block); + } +} diff --git a/cipher/src/tweak/zero.rs b/cipher/src/tweak/zero.rs new file mode 100644 index 000000000..9bebf1a90 --- /dev/null +++ b/cipher/src/tweak/zero.rs @@ -0,0 +1,118 @@ +use core::marker::PhantomData; + +use crypto_common::{array::ArraySize, Block, BlockSizes, ParBlocksSizeUser}; + +use super::{ + TweakBlockCipherDecBackend, TweakBlockCipherDecClosure, TweakBlockCipherDecrypt, + TweakBlockCipherEncBackend, TweakBlockCipherEncrypt, TweakSizeUser, +}; +use crate::{ + consts::U1, tweak::TweakBlockCipherEncClosure, BlockCipherDecBackend, BlockCipherDecClosure, + BlockCipherDecrypt, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, + BlockSizeUser, +}; + +/// Wrapper around tweakable block cipher which implements +/// the [common block cipher traits][crate::block] using zero tweak. +#[derive(Debug, Clone)] +pub struct ZeroTweak(pub C); + +impl BlockSizeUser for ZeroTweak { + type BlockSize = C::BlockSize; +} + +impl BlockCipherEncrypt for ZeroTweak { + #[inline] + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + self.0.encrypt_with_backend(ClosureWrapper { + f, + _pd: PhantomData, + }); + } +} + +impl BlockCipherDecrypt for ZeroTweak { + #[inline] + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + self.0.decrypt_with_backend(ClosureWrapper { + f, + _pd: PhantomData, + }); + } +} + +/// Wrapper around non-tweakble block cipher closures which implements the tweakable +/// block cipher closure traits using zero tweak. +struct ClosureWrapper { + f: F, + _pd: PhantomData<(TS, BS)>, +} + +impl BlockSizeUser for ClosureWrapper { + type BlockSize = BS; +} + +impl TweakSizeUser for ClosureWrapper { + type TweakSize = TS; +} + +impl TweakBlockCipherEncClosure for ClosureWrapper +where + F: BlockCipherEncClosure, +{ + #[inline] + fn call>(self, backend: &B) { + self.f.call(&BackendWrapper { + backend, + _pd: PhantomData, + }) + } +} + +impl TweakBlockCipherDecClosure for ClosureWrapper +where + F: BlockCipherDecClosure, +{ + #[inline] + fn call>(self, backend: &B) { + self.f.call(&BackendWrapper { + backend, + _pd: PhantomData, + }) + } +} + +/// Wrapper around tweakable block cipher backend which implements non-tweakable +/// block cipher backend traits using zero tweak. +struct BackendWrapper<'a, BS: BlockSizes, B> { + backend: &'a B, + _pd: PhantomData, +} + +impl BlockSizeUser for BackendWrapper<'_, BS, B> { + type BlockSize = BS; +} + +impl ParBlocksSizeUser for BackendWrapper<'_, BS, B> { + type ParBlocksSize = U1; +} + +impl BlockCipherEncBackend for BackendWrapper<'_, BS, B> +where + B: TweakBlockCipherEncBackend, +{ + #[inline] + fn encrypt_block(&self, block: inout::InOut<'_, '_, Block>) { + self.backend.encrypt_block_inout(&Default::default(), block); + } +} + +impl BlockCipherDecBackend for BackendWrapper<'_, BS, B> +where + B: TweakBlockCipherDecBackend, +{ + #[inline] + fn decrypt_block(&self, block: inout::InOut<'_, '_, Block>) { + self.backend.decrypt_block_inout(&Default::default(), block); + } +}