diff --git a/block-padding/CHANGELOG.md b/block-padding/CHANGELOG.md index 4a21889e..e1171828 100644 --- a/block-padding/CHANGELOG.md +++ b/block-padding/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.4.0 (unreleased) ### Added -- `Padding::pad_detached` method ([#1225]) +- `Padding::pad_detached` method ([#1225], [#1227]) +- `PaddedData` enum ([#1227]) ### Changed - Migrated from `generic-array` to `hybrid-array` ([#944]) @@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#1149]: https://github.com/RustCrypto/utils/pull/1149 [#1217]: https://github.com/RustCrypto/utils/pull/1217 [#1225]: https://github.com/RustCrypto/utils/pull/1225 +[#1227]: https://github.com/RustCrypto/utils/pull/1227 ## 0.3.3 (2023-04-02) ### Added diff --git a/block-padding/src/lib.rs b/block-padding/src/lib.rs index 7fe9da7a..9b195bc9 100644 --- a/block-padding/src/lib.rs +++ b/block-padding/src/lib.rs @@ -48,21 +48,18 @@ pub trait Padding { /// Pad message and return padded tail block. /// - /// `Err` is returned only by [`NoPadding`] if `data` length is not multiple of the block size. - /// [`NoPadding`] and [`ZeroPadding`] return `Ok((blocks, None))` if `data` length - /// is multiple of block size. All other padding implementations should always return - /// `Ok((blocks, Some(tail_block)))`. - #[allow(clippy::type_complexity)] + /// [`PaddedData::Error`] is returned only by [`NoPadding`] if `data` length is not multiple + /// of the block size. [`NoPadding`] and [`ZeroPadding`] return [`PaddedData::NoPad`] + /// if `data` length is multiple of block size. All other padding implementations + /// should always return [`PaddedData::Pad`]. #[inline] - fn pad_detached( - data: &[u8], - ) -> Result<(&[Array], Option>), Error> { + fn pad_detached(data: &[u8]) -> PaddedData<'_, BlockSize> { let (blocks, tail) = Array::slice_as_chunks(data); let mut tail_block = Array::default(); let pos = tail.len(); tail_block[..pos].copy_from_slice(tail); Self::pad(&mut tail_block, pos); - Ok((blocks, Some(tail_block))) + PaddedData::Pad { blocks, tail_block } } /// Unpad data in `blocks` and return unpadded byte slice. @@ -120,6 +117,19 @@ impl Padding for ZeroPadding { Ok(&block[..0]) } + #[inline] + fn pad_detached(data: &[u8]) -> PaddedData<'_, BlockSize> { + let (blocks, tail) = Array::slice_as_chunks(data); + if tail.is_empty() { + return PaddedData::NoPad { blocks }; + } + let mut tail_block = Array::default(); + let pos = tail.len(); + tail_block[..pos].copy_from_slice(tail); + Self::pad(&mut tail_block, pos); + PaddedData::Pad { blocks, tail_block } + } + #[inline] fn unpad_blocks(blocks: &[Array]) -> Result<&[u8], Error> { let buf = Array::slice_as_flattened(blocks); @@ -353,6 +363,16 @@ impl Padding for NoPadding { Ok(block) } + #[inline] + fn pad_detached(data: &[u8]) -> PaddedData<'_, BlockSize> { + let (blocks, tail) = Array::slice_as_chunks(data); + if tail.is_empty() { + PaddedData::NoPad { blocks } + } else { + PaddedData::Error + } + } + #[inline] fn unpad_blocks(blocks: &[Array]) -> Result<&[u8], Error> { Ok(Array::slice_as_flattened(blocks)) @@ -370,3 +390,37 @@ impl fmt::Display for Error { } impl core::error::Error for Error {} + +/// Padded data split into blocks with detached last block returned by [`Padding::pad_detached`]. +#[derive(Debug)] +pub enum PaddedData<'a, BlockSize: ArraySize> { + /// Message split into blocks with detached and padded `tail_block`. + Pad { + /// Message blocks. + blocks: &'a [Array], + /// Last message block with padding. + tail_block: Array, + }, + /// [`NoPadding`] or [`ZeroPadding`] were used on a message which does not require any padding. + NoPad { + /// Message blocks. + blocks: &'a [Array], + }, + /// [`NoPadding`] was used on a message with size not multiple of the block size. + Error, +} + +impl<'a, BlockSize: ArraySize> PaddedData<'a, BlockSize> { + /// Unwrap the `Pad` variant. + pub fn unwrap(self) -> (&'a [Array], Array) { + match self { + PaddedData::Pad { blocks, tail_block } => (blocks, tail_block), + PaddedData::NoPad { .. } => { + panic!("Expected `PaddedData::Pad`, but got `PaddedData::NoPad`"); + } + PaddedData::Error => { + panic!("Expected `PaddedData::Pad`, but got `PaddedData::Error`"); + } + } + } +} diff --git a/inout/src/reserved.rs b/inout/src/reserved.rs index ab143dfe..95152c17 100644 --- a/inout/src/reserved.rs +++ b/inout/src/reserved.rs @@ -160,7 +160,13 @@ impl<'inp, 'out> InOutBufReserved<'inp, 'out, u8> { { let bs = BS::USIZE; let blocks_len = self.in_len / bs; - let (blocks, tail_block) = P::pad_detached(self.get_in()).map_err(|_| PadError)?; + + use block_padding::PaddedData; + let (blocks, tail_block) = match P::pad_detached(self.get_in()) { + PaddedData::Pad { blocks, tail_block } => (blocks, Some(tail_block)), + PaddedData::NoPad { blocks } => (blocks, None), + PaddedData::Error => return Err(PadError), + }; assert_eq!(blocks.len(), blocks_len);