diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 5c8e83365..f3f7d4ac9 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -25,6 +25,8 @@ jobs: override: true profile: minimal - run: cargo clippy --all --all-features -- -D warnings + - run: cargo clippy --all --all-features -- -D warnings + working-directory: cipher - run: cargo clippy --all --all-features -- -D warnings working-directory: crypto - run: cargo clippy --all --all-features -- -D warnings diff --git a/cipher/CHANGELOG.md b/cipher/CHANGELOG.md index 7eee95adc..1ece484db 100644 --- a/cipher/CHANGELOG.md +++ b/cipher/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## UNRELEASED +### Added +- Allocating padded encrypt/decrypt ([#936]) + +[#936]: https://github.com/RustCrypto/traits/pull/936 + ## 0.3.0 (2022-02-10) ### Changed - Major rework of traits. Core functionality of block and stream ciphers diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index 4ef3d2a6e..572275234 100644 --- a/cipher/Cargo.toml +++ b/cipher/Cargo.toml @@ -25,7 +25,9 @@ blobby = { version = "0.3", optional = true } zeroize = { version = "1.5", optional = true, default-features = false } [features] -std = ["crypto-common/std", "inout/std"] +default = ["alloc"] +alloc = [] +std = ["alloc", "crypto-common/std", "inout/std"] block-padding = ["inout/block-padding"] rand_core = ["crypto-common/rand_core"] # Enable random key and IV generation methods dev = ["blobby"] diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 9c22fe3e8..697e42e6f 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -11,6 +11,8 @@ //! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm use crate::{ParBlocks, ParBlocksSizeUser}; +#[cfg(all(feature = "block-padding", feature = "alloc"))] +use alloc::{vec, vec::Vec}; #[cfg(feature = "block-padding")] use inout::{ block_padding::{Padding, UnpadError}, @@ -173,6 +175,20 @@ pub trait BlockEncrypt: BlockSizeUser + Sized { let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?; self.encrypt_padded_inout::

(buf) } + + /// Pad input and encrypt into a newly allocated Vec. Returns resulting ciphertext Vec. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn encrypt_padded_vec>(&self, msg: &[u8]) -> Vec { + let mut out = allocate_out_vec::(msg.len()); + let len = self + .encrypt_padded_b2b::

(msg, &mut out) + .expect("enough space for encrypting is allocated") + .len(); + out.truncate(len); + out + } } /// Decrypt-only functionality for block ciphers. @@ -281,6 +297,24 @@ pub trait BlockDecrypt: BlockSizeUser { let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?; self.decrypt_padded_inout::

(buf) } + + /// Decrypt input and unpad it in a newly allocated Vec. Returns resulting + /// ciphertext Vec. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn decrypt_padded_vec>( + &self, + buf: &[u8], + ) -> Result, UnpadError> { + let mut out = vec![0; buf.len()]; + let len = self.decrypt_padded_b2b::

(buf, &mut out)?.len(); + out.truncate(len); + Ok(out) + } } /// Encrypt-only functionality for block ciphers and modes with mutable access to `self`. @@ -363,11 +397,11 @@ pub trait BlockEncryptMut: BlockSizeUser + Sized { #[cfg(feature = "block-padding")] #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] #[inline] - fn encrypt_padded_mut<'a, P: Padding>( + fn encrypt_padded_mut>( self, - buf: &'a mut [u8], + buf: &mut [u8], msg_len: usize, - ) -> Result<&'a [u8], PadError> { + ) -> Result<&[u8], PadError> { let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?; self.encrypt_padded_inout_mut::

(buf) } @@ -386,6 +420,20 @@ pub trait BlockEncryptMut: BlockSizeUser + Sized { let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?; self.encrypt_padded_inout_mut::

(buf) } + + /// Pad input and encrypt into a newly allocated Vec. Returns resulting ciphertext Vec. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn encrypt_padded_vec_mut>(self, msg: &[u8]) -> Vec { + let mut out = allocate_out_vec::(msg.len()); + let len = self + .encrypt_padded_b2b_mut::

(msg, &mut out) + .expect("enough space for encrypting is allocated") + .len(); + out.truncate(len); + out + } } /// Decrypt-only functionality for block ciphers and modes with mutable access to `self`. @@ -470,10 +518,10 @@ pub trait BlockDecryptMut: BlockSizeUser + Sized { #[cfg(feature = "block-padding")] #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] #[inline] - fn decrypt_padded_mut<'a, P: Padding>( + fn decrypt_padded_mut>( self, - buf: &'a mut [u8], - ) -> Result<&'a [u8], UnpadError> { + buf: &mut [u8], + ) -> Result<&[u8], UnpadError> { self.decrypt_padded_inout_mut::

(buf.into()) } @@ -498,6 +546,24 @@ pub trait BlockDecryptMut: BlockSizeUser + Sized { let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?; self.decrypt_padded_inout_mut::

(buf) } + + /// Decrypt input and unpad it in a newly allocated Vec. Returns resulting + /// ciphertext Vec. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn decrypt_padded_vec>( + self, + buf: &[u8], + ) -> Result, UnpadError> { + let mut out = vec![0; buf.len()]; + let len = self.decrypt_padded_b2b_mut::

(buf, &mut out)?.len(); + out.truncate(len); + Ok(out) + } } impl BlockEncryptMut for Alg { @@ -568,6 +634,12 @@ impl<'inp, 'out, BS: ArrayLength> BlockClosure for BlocksCtx<'inp, 'out, BS> } } +#[cfg(all(feature = "block-padding", feature = "alloc"))] +fn allocate_out_vec(len: usize) -> Vec { + let bs = BS::BlockSize::USIZE; + vec![0; bs * (len / bs + 1)] +} + /// Implement simple block backend #[macro_export] macro_rules! impl_simple_block_encdec { diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index fff7fd98e..102fa35a7 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -17,6 +17,9 @@ pub use crypto_common; pub use inout; +#[cfg(all(feature = "block-padding", feature = "alloc"))] +extern crate alloc; + #[cfg(feature = "std")] extern crate std;