chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

721
vendor/cipher/src/block.rs vendored Normal file
View File

@@ -0,0 +1,721 @@
//! Traits used to define functionality of [block ciphers][1] and [modes of operation][2].
//!
//! # About block ciphers
//!
//! Block ciphers are keyed, deterministic permutations of a fixed-sized input
//! "block" providing a reversible transformation to/from an encrypted output.
//! They are one of the fundamental structural components of [symmetric cryptography][3].
//!
//! [1]: https://en.wikipedia.org/wiki/Block_cipher
//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
//! [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},
InOutBufReserved, PadError,
};
use inout::{InOut, InOutBuf, NotEqualError};
pub use crypto_common::{generic_array::ArrayLength, typenum::Unsigned, Block, BlockSizeUser};
/// Marker trait for block ciphers.
pub trait BlockCipher: BlockSizeUser {}
/// Trait implemented by block cipher encryption and decryption backends.
pub trait BlockBackend: ParBlocksSizeUser {
/// Process single inout block.
fn proc_block(&mut self, block: InOut<'_, '_, Block<Self>>);
/// Process inout blocks in parallel.
#[inline(always)]
fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks<Self>>) {
for i in 0..Self::ParBlocksSize::USIZE {
self.proc_block(blocks.get(i));
}
}
/// Process buffer of inout blocks. Length of the buffer MUST be smaller
/// than `Self::ParBlocksSize`.
#[inline(always)]
fn proc_tail_blocks(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
assert!(blocks.len() < Self::ParBlocksSize::USIZE);
for block in blocks {
self.proc_block(block);
}
}
/// Process single block in-place.
#[inline(always)]
fn proc_block_inplace(&mut self, block: &mut Block<Self>) {
self.proc_block(block.into());
}
/// Process blocks in parallel in-place.
#[inline(always)]
fn proc_par_blocks_inplace(&mut self, blocks: &mut ParBlocks<Self>) {
self.proc_par_blocks(blocks.into());
}
/// Process buffer of blocks in-place. Length of the buffer MUST be smaller
/// than `Self::ParBlocksSize`.
#[inline(always)]
fn proc_tail_blocks_inplace(&mut self, blocks: &mut [Block<Self>]) {
self.proc_tail_blocks(blocks.into());
}
}
/// Trait for [`BlockBackend`] users.
///
/// This trait is used to define rank-2 closures.
pub trait BlockClosure: BlockSizeUser {
/// Execute closure with the provided block cipher backend.
fn call<B: BlockBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
}
/// Encrypt-only functionality for block ciphers.
pub trait BlockEncrypt: BlockSizeUser + Sized {
/// Encrypt data using backend provided to the rank-2 closure.
fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
/// Encrypt single `inout` block.
#[inline]
fn encrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
self.encrypt_with_backend(BlockCtx { block });
}
/// Encrypt `inout` blocks.
#[inline]
fn encrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.encrypt_with_backend(BlocksCtx { blocks });
}
/// Encrypt single block in-place.
#[inline]
fn encrypt_block(&self, block: &mut Block<Self>) {
let block = block.into();
self.encrypt_with_backend(BlockCtx { block });
}
/// Encrypt `in_block` and write result to `out_block`.
#[inline]
fn encrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.encrypt_with_backend(BlockCtx { block });
}
/// Encrypt blocks in-place.
#[inline]
fn encrypt_blocks(&self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.encrypt_with_backend(BlocksCtx { blocks });
}
/// Encrypt blocks buffer-to-buffer.
///
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
fn encrypt_blocks_b2b(
&self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
}
/// Pad input and encrypt. Returns resulting ciphertext slice.
///
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn encrypt_padded_inout<'inp, 'out, P: Padding<Self::BlockSize>>(
&self,
data: InOutBufReserved<'inp, 'out, u8>,
) -> Result<&'out [u8], PadError> {
let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
self.encrypt_blocks_inout(buf.get_blocks());
if let Some(block) = buf.get_tail_block() {
self.encrypt_block_inout(block);
}
Ok(buf.into_out())
}
/// Pad input and encrypt in-place. Returns resulting ciphertext slice.
///
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn encrypt_padded<'a, P: Padding<Self::BlockSize>>(
&self,
buf: &'a mut [u8],
msg_len: usize,
) -> Result<&'a [u8], PadError> {
let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
self.encrypt_padded_inout::<P>(buf)
}
/// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice.
///
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn encrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
&self,
msg: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], PadError> {
let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
self.encrypt_padded_inout::<P>(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<P: Padding<Self::BlockSize>>(&self, msg: &[u8]) -> Vec<u8> {
let mut out = allocate_out_vec::<Self>(msg.len());
let len = self
.encrypt_padded_b2b::<P>(msg, &mut out)
.expect("enough space for encrypting is allocated")
.len();
out.truncate(len);
out
}
}
/// Decrypt-only functionality for block ciphers.
pub trait BlockDecrypt: BlockSizeUser {
/// Decrypt data using backend provided to the rank-2 closure.
fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
/// Decrypt single `inout` block.
#[inline]
fn decrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
self.decrypt_with_backend(BlockCtx { block });
}
/// Decrypt `inout` blocks.
#[inline]
fn decrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.decrypt_with_backend(BlocksCtx { blocks });
}
/// Decrypt single block in-place.
#[inline]
fn decrypt_block(&self, block: &mut Block<Self>) {
let block = block.into();
self.decrypt_with_backend(BlockCtx { block });
}
/// Decrypt `in_block` and write result to `out_block`.
#[inline]
fn decrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.decrypt_with_backend(BlockCtx { block });
}
/// Decrypt blocks in-place.
#[inline]
fn decrypt_blocks(&self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.decrypt_with_backend(BlocksCtx { blocks });
}
/// Decrypt blocks buffer-to-buffer.
///
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
fn decrypt_blocks_b2b(
&self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
}
/// Decrypt input and unpad it. Returns resulting ciphertext slice.
///
/// Returns [`UnpadError`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn decrypt_padded_inout<'inp, 'out, P: Padding<Self::BlockSize>>(
&self,
data: InOutBuf<'inp, 'out, u8>,
) -> Result<&'out [u8], UnpadError> {
let (mut blocks, tail) = data.into_chunks();
if !tail.is_empty() {
return Err(UnpadError);
}
self.decrypt_blocks_inout(blocks.reborrow());
P::unpad_blocks(blocks.into_out())
}
/// Decrypt input and unpad it in-place. Returns resulting ciphertext slice.
///
/// Returns [`UnpadError`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn decrypt_padded<'a, P: Padding<Self::BlockSize>>(
&self,
buf: &'a mut [u8],
) -> Result<&'a [u8], UnpadError> {
self.decrypt_padded_inout::<P>(buf.into())
}
/// Decrypt input and unpad it buffer-to-buffer. Returns resulting
/// ciphertext slice.
///
/// Returns [`UnpadError`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn decrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
&self,
in_buf: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], UnpadError> {
if out_buf.len() < in_buf.len() {
return Err(UnpadError);
}
let n = in_buf.len();
// note: `new` always returns `Ok` here
let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?;
self.decrypt_padded_inout::<P>(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<P: Padding<Self::BlockSize>>(
&self,
buf: &[u8],
) -> Result<Vec<u8>, UnpadError> {
let mut out = vec![0; buf.len()];
let len = self.decrypt_padded_b2b::<P>(buf, &mut out)?.len();
out.truncate(len);
Ok(out)
}
}
/// Encrypt-only functionality for block ciphers and modes with mutable access to `self`.
///
/// The main use case for this trait is blocks modes, but it also can be used
/// for hardware cryptographic engines which require `&mut self` access to an
/// underlying hardware peripheral.
pub trait BlockEncryptMut: BlockSizeUser + Sized {
/// Encrypt data using backend provided to the rank-2 closure.
fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
/// Encrypt single `inout` block.
#[inline]
fn encrypt_block_inout_mut(&mut self, block: InOut<'_, '_, Block<Self>>) {
self.encrypt_with_backend_mut(BlockCtx { block });
}
/// Encrypt `inout` blocks.
#[inline]
fn encrypt_blocks_inout_mut(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.encrypt_with_backend_mut(BlocksCtx { blocks });
}
/// Encrypt single block in-place.
#[inline]
fn encrypt_block_mut(&mut self, block: &mut Block<Self>) {
let block = block.into();
self.encrypt_with_backend_mut(BlockCtx { block });
}
/// Encrypt `in_block` and write result to `out_block`.
#[inline]
fn encrypt_block_b2b_mut(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.encrypt_with_backend_mut(BlockCtx { block });
}
/// Encrypt blocks in-place.
#[inline]
fn encrypt_blocks_mut(&mut self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.encrypt_with_backend_mut(BlocksCtx { blocks });
}
/// Encrypt blocks buffer-to-buffer.
///
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
fn encrypt_blocks_b2b_mut(
&mut self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.encrypt_with_backend_mut(BlocksCtx { blocks }))
}
/// Pad input and encrypt. Returns resulting ciphertext slice.
///
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn encrypt_padded_inout_mut<'inp, 'out, P: Padding<Self::BlockSize>>(
mut self,
data: InOutBufReserved<'inp, 'out, u8>,
) -> Result<&'out [u8], PadError> {
let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
self.encrypt_blocks_inout_mut(buf.get_blocks());
if let Some(block) = buf.get_tail_block() {
self.encrypt_block_inout_mut(block);
}
Ok(buf.into_out())
}
/// Pad input and encrypt in-place. Returns resulting ciphertext slice.
///
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn encrypt_padded_mut<P: Padding<Self::BlockSize>>(
self,
buf: &mut [u8],
msg_len: usize,
) -> Result<&[u8], PadError> {
let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
self.encrypt_padded_inout_mut::<P>(buf)
}
/// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice.
///
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn encrypt_padded_b2b_mut<'a, P: Padding<Self::BlockSize>>(
self,
msg: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], PadError> {
let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
self.encrypt_padded_inout_mut::<P>(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<P: Padding<Self::BlockSize>>(self, msg: &[u8]) -> Vec<u8> {
let mut out = allocate_out_vec::<Self>(msg.len());
let len = self
.encrypt_padded_b2b_mut::<P>(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`.
///
/// The main use case for this trait is blocks modes, but it also can be used
/// for hardware cryptographic engines which require `&mut self` access to an
/// underlying hardware peripheral.
pub trait BlockDecryptMut: BlockSizeUser + Sized {
/// Decrypt data using backend provided to the rank-2 closure.
fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
/// Decrypt single `inout` block.
#[inline]
fn decrypt_block_inout_mut(&mut self, block: InOut<'_, '_, Block<Self>>) {
self.decrypt_with_backend_mut(BlockCtx { block });
}
/// Decrypt `inout` blocks.
#[inline]
fn decrypt_blocks_inout_mut(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.decrypt_with_backend_mut(BlocksCtx { blocks });
}
/// Decrypt single block in-place.
#[inline]
fn decrypt_block_mut(&mut self, block: &mut Block<Self>) {
let block = block.into();
self.decrypt_with_backend_mut(BlockCtx { block });
}
/// Decrypt `in_block` and write result to `out_block`.
#[inline]
fn decrypt_block_b2b_mut(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.decrypt_with_backend_mut(BlockCtx { block });
}
/// Decrypt blocks in-place.
#[inline]
fn decrypt_blocks_mut(&mut self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.decrypt_with_backend_mut(BlocksCtx { blocks });
}
/// Decrypt blocks buffer-to-buffer.
///
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
fn decrypt_blocks_b2b_mut(
&mut self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.decrypt_with_backend_mut(BlocksCtx { blocks }))
}
/// Decrypt input and unpad it. Returns resulting ciphertext slice.
///
/// Returns [`UnpadError`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn decrypt_padded_inout_mut<'inp, 'out, P: Padding<Self::BlockSize>>(
mut self,
data: InOutBuf<'inp, 'out, u8>,
) -> Result<&'out [u8], UnpadError> {
let (mut blocks, tail) = data.into_chunks();
if !tail.is_empty() {
return Err(UnpadError);
}
self.decrypt_blocks_inout_mut(blocks.reborrow());
P::unpad_blocks(blocks.into_out())
}
/// Decrypt input and unpad it in-place. Returns resulting ciphertext slice.
///
/// Returns [`UnpadError`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn decrypt_padded_mut<P: Padding<Self::BlockSize>>(
self,
buf: &mut [u8],
) -> Result<&[u8], UnpadError> {
self.decrypt_padded_inout_mut::<P>(buf.into())
}
/// Decrypt input and unpad it buffer-to-buffer. Returns resulting
/// ciphertext slice.
///
/// Returns [`UnpadError`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
#[inline]
fn decrypt_padded_b2b_mut<'a, P: Padding<Self::BlockSize>>(
self,
in_buf: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], UnpadError> {
if out_buf.len() < in_buf.len() {
return Err(UnpadError);
}
let n = in_buf.len();
// note: `new` always returns `Ok` here
let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?;
self.decrypt_padded_inout_mut::<P>(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_mut<P: Padding<Self::BlockSize>>(
self,
buf: &[u8],
) -> Result<Vec<u8>, UnpadError> {
let mut out = vec![0; buf.len()];
let len = self.decrypt_padded_b2b_mut::<P>(buf, &mut out)?.len();
out.truncate(len);
Ok(out)
}
}
impl<Alg: BlockEncrypt> BlockEncryptMut for Alg {
fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
self.encrypt_with_backend(f);
}
}
impl<Alg: BlockDecrypt> BlockDecryptMut for Alg {
fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
self.decrypt_with_backend(f);
}
}
impl<Alg: BlockCipher> BlockCipher for &Alg {}
impl<Alg: BlockEncrypt> BlockEncrypt for &Alg {
fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
Alg::encrypt_with_backend(self, f);
}
}
impl<Alg: BlockDecrypt> BlockDecrypt for &Alg {
fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
Alg::decrypt_with_backend(self, f);
}
}
/// Closure used in methods which operate over separate blocks.
struct BlockCtx<'inp, 'out, BS: ArrayLength<u8>> {
block: InOut<'inp, 'out, Block<Self>>,
}
impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for BlockCtx<'inp, 'out, BS> {
type BlockSize = BS;
}
impl<'inp, 'out, BS: ArrayLength<u8>> BlockClosure for BlockCtx<'inp, 'out, BS> {
#[inline(always)]
fn call<B: BlockBackend<BlockSize = BS>>(self, backend: &mut B) {
backend.proc_block(self.block);
}
}
/// Closure used in methods which operate over slice of blocks.
struct BlocksCtx<'inp, 'out, BS: ArrayLength<u8>> {
blocks: InOutBuf<'inp, 'out, Block<Self>>,
}
impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for BlocksCtx<'inp, 'out, BS> {
type BlockSize = BS;
}
impl<'inp, 'out, BS: ArrayLength<u8>> BlockClosure for BlocksCtx<'inp, 'out, BS> {
#[inline(always)]
fn call<B: BlockBackend<BlockSize = BS>>(self, backend: &mut B) {
if B::ParBlocksSize::USIZE > 1 {
let (chunks, tail) = self.blocks.into_chunks();
for chunk in chunks {
backend.proc_par_blocks(chunk);
}
backend.proc_tail_blocks(tail);
} else {
for block in self.blocks {
backend.proc_block(block);
}
}
}
}
#[cfg(all(feature = "block-padding", feature = "alloc"))]
fn allocate_out_vec<BS: BlockSizeUser>(len: usize) -> Vec<u8> {
let bs = BS::BlockSize::USIZE;
vec![0; bs * (len / bs + 1)]
}
/// Implement simple block backend
#[macro_export]
macro_rules! impl_simple_block_encdec {
(
<$($N:ident$(:$b0:ident$(+$b:ident)*)?),*>
$cipher:ident, $block_size:ty, $state:ident, $block:ident,
encrypt: $enc_block:block
decrypt: $dec_block:block
) => {
impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockSizeUser for $cipher<$($N),*> {
type BlockSize = $block_size;
}
impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockEncrypt for $cipher<$($N),*> {
fn encrypt_with_backend(&self, f: impl $crate::BlockClosure<BlockSize = $block_size>) {
struct EncBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>);
impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for EncBack<'a, $($N),*> {
type BlockSize = $block_size;
}
impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for EncBack<'a, $($N),*> {
type ParBlocksSize = $crate::consts::U1;
}
impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for EncBack<'a, $($N),*> {
#[inline(always)]
fn proc_block(
&mut self,
mut $block: $crate::inout::InOut<'_, '_, $crate::Block<Self>>
) {
let $state: &$cipher<$($N),*> = self.0;
$enc_block
}
}
f.call(&mut EncBack(self))
}
}
impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockDecrypt for $cipher<$($N),*> {
fn decrypt_with_backend(&self, f: impl $crate::BlockClosure<BlockSize = $block_size>) {
struct DecBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>);
impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for DecBack<'a, $($N),*> {
type BlockSize = $block_size;
}
impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for DecBack<'a, $($N),*> {
type ParBlocksSize = $crate::consts::U1;
}
impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for DecBack<'a, $($N),*> {
#[inline(always)]
fn proc_block(
&mut self,
mut $block: $crate::inout::InOut<'_, '_, $crate::Block<Self>>
) {
let $state: &$cipher<$($N),*> = self.0;
$dec_block
}
}
f.call(&mut DecBack(self))
}
}
};
(
$cipher:ident, $block_size:ty, $state:ident, $block:ident,
encrypt: $enc_block:block
decrypt: $dec_block:block
) => {
$crate::impl_simple_block_encdec!(
<> $cipher, $block_size, $state, $block,
encrypt: $enc_block
decrypt: $dec_block
);
};
}

2
vendor/cipher/src/dev.rs vendored Normal file
View File

@@ -0,0 +1,2 @@
mod block;
mod stream;

389
vendor/cipher/src/dev/block.rs vendored Normal file
View File

@@ -0,0 +1,389 @@
//! Development-related functionality
pub use blobby;
/// Define block cipher test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_cipher_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::{
blobby::Blob3Iterator, generic_array::GenericArray, typenum::Unsigned,
BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyInit,
};
fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool {
let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap();
let mut block = GenericArray::clone_from_slice(pt);
state.encrypt_block_mut(&mut block);
if ct != block.as_slice() {
return false;
}
state.decrypt_block_mut(&mut block);
if pt != block.as_slice() {
return false;
}
true
}
fn run_par_test(key: &[u8], pt: &[u8]) -> bool {
type Block = cipher::Block<$cipher>;
let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap();
let block = Block::clone_from_slice(pt);
let mut blocks1 = vec![block; 101];
for (i, b) in blocks1.iter_mut().enumerate() {
*b = block;
b[0] = b[0].wrapping_add(i as u8);
}
let mut blocks2 = blocks1.clone();
// check that `encrypt_blocks` and `encrypt_block`
// result in the same ciphertext
state.encrypt_blocks_mut(&mut blocks1);
for b in blocks2.iter_mut() {
state.encrypt_block_mut(b);
}
if blocks1 != blocks2 {
return false;
}
// check that `encrypt_blocks` and `encrypt_block`
// result in the same plaintext
state.decrypt_blocks_mut(&mut blocks1);
for b in blocks2.iter_mut() {
state.decrypt_block_mut(b);
}
if blocks1 != blocks2 {
return false;
}
true
}
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() {
let [key, pt, ct] = row.unwrap();
if !run_test(key, pt, ct) {
panic!(
"\n\
Failed test №{}\n\
key:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, pt, ct,
);
}
// test parallel blocks encryption/decryption
if !run_par_test(key, pt) {
panic!(
"\n\
Failed parallel test №{}\n\
key:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, pt, ct,
);
}
}
}
};
}
/// Define block mode encryption test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_mode_enc_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::{
blobby::Blob4Iterator, generic_array::GenericArray, inout::InOutBuf,
typenum::Unsigned, BlockEncryptMut, BlockSizeUser, KeyIvInit,
};
fn run_test(key: &[u8], iv: &[u8], pt: &[u8], ct: &[u8]) -> bool {
assert_eq!(pt.len(), ct.len());
// test block-by-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
let mut out = vec![0u8; ct.len()];
let mut buf = InOutBuf::new(pt, &mut out).unwrap();
let (blocks, tail) = buf.reborrow().into_chunks();
assert_eq!(tail.len(), 0);
for block in blocks {
state.encrypt_block_inout_mut(block);
}
if buf.get_out() != ct {
return false;
}
// test multi-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
buf.get_out().iter_mut().for_each(|b| *b = 0);
let (blocks, _) = buf.reborrow().into_chunks();
state.encrypt_blocks_inout_mut(blocks);
if buf.get_out() != ct {
return false;
}
true
}
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() {
let [key, iv, pt, ct] = row.unwrap();
if !run_test(key, iv, pt, ct) {
panic!(
"\n\
Failed test №{}\n\
key:\t{:?}\n\
iv:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, iv, pt, ct,
);
}
}
}
};
}
/// Define block mode decryption test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_mode_dec_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::{
blobby::Blob4Iterator, generic_array::GenericArray, inout::InOutBuf,
typenum::Unsigned, BlockDecryptMut, BlockSizeUser, KeyIvInit,
};
fn run_test(key: &[u8], iv: &[u8], pt: &[u8], ct: &[u8]) -> bool {
assert_eq!(pt.len(), ct.len());
// test block-by-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
let mut out = vec![0u8; pt.len()];
let mut buf = InOutBuf::new(ct, &mut out).unwrap();
let (blocks, tail) = buf.reborrow().into_chunks();
assert_eq!(tail.len(), 0);
for block in blocks {
state.decrypt_block_inout_mut(block);
}
if buf.get_out() != pt {
return false;
}
// test multi-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
buf.get_out().iter_mut().for_each(|b| *b = 0);
let (blocks, _) = buf.reborrow().into_chunks();
state.decrypt_blocks_inout_mut(blocks);
if buf.get_out() != pt {
return false;
}
true
}
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() {
let [key, iv, pt, ct] = row.unwrap();
if !run_test(key, iv, pt, ct) {
panic!(
"\n\
Failed test №{}\n\
key:\t{:?}\n\
iv:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, iv, pt, ct,
);
}
}
}
};
}
/// Define `IvState` test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! iv_state_test {
($name:ident, $cipher:ty, encrypt $(,)?) => {
$crate::iv_state_test!($name, $cipher, encrypt_blocks_mut);
};
($name:ident, $cipher:ty, decrypt $(,)?) => {
$crate::iv_state_test!($name, $cipher, decrypt_blocks_mut);
};
($name:ident, $cipher:ty, apply_ks $(,)?) => {
$crate::iv_state_test!($name, $cipher, apply_keystream_blocks);
};
($name:ident, $cipher:ty, $method:ident $(,)?) => {
#[test]
fn $name() {
use cipher::*;
let mut blocks = [Block::<$cipher>::default(); 32];
for (i, block) in blocks.iter_mut().enumerate() {
for (j, b) in block.iter_mut().enumerate() {
*b = (i + j) as u8;
}
}
let mut key = Key::<$cipher>::default();
let mut iv = Iv::<$cipher>::default();
key.iter_mut().for_each(|b| *b = 0x42);
iv.iter_mut().for_each(|b| *b = 0x24);
let mut cipher = <$cipher>::new(&key, &iv);
let mut target = blocks.clone();
cipher.$method(&mut target);
for i in 0..32 {
let mut blocks = blocks.clone();
let (b1, b2) = blocks.split_at_mut(i);
let mut cipher1 = <$cipher>::new(&key, &iv);
cipher1.$method(b1);
let temp_iv = cipher1.iv_state();
let mut cipher2 = <$cipher>::new(&key, &temp_iv);
cipher2.$method(b2);
assert_eq!(blocks, target);
}
}
};
}
/// Define block encryptor benchmark
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_encryptor_bench {
(Key: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_encryptor_bench!(
{
use $crate::KeyInit;
let key = test::black_box(Default::default());
<$cipher>::new(&key)
},
$cipher,
$block_name,
$blocks_name,
);
};
(KeyIv: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_encryptor_bench!(
{
use $crate::KeyIvInit;
let key = test::black_box(Default::default());
let iv = test::black_box(Default::default());
<$cipher>::new(&key, &iv)
},
$cipher,
$block_name,
$blocks_name,
);
};
($init:block, $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
#[bench]
pub fn $block_name(bh: &mut test::Bencher) {
use cipher::BlockEncryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
for block in blocks.iter_mut() {
cipher.encrypt_block_mut(block);
}
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
#[bench]
pub fn $blocks_name(bh: &mut test::Bencher) {
use cipher::BlockEncryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
cipher.encrypt_blocks_mut(&mut blocks);
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
};
}
/// Define block decryptor benchmark
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_decryptor_bench {
(Key: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_decryptor_bench!(
{
use $crate::KeyInit;
let key = test::black_box(Default::default());
<$cipher>::new(&key)
},
$cipher,
$block_name,
$blocks_name,
);
};
(KeyIv: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_decryptor_bench!(
{
use $crate::KeyIvInit;
let key = test::black_box(Default::default());
let iv = test::black_box(Default::default());
<$cipher>::new(&key, &iv)
},
$cipher,
$block_name,
$blocks_name,
);
};
($init:block, $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
#[bench]
pub fn $block_name(bh: &mut test::Bencher) {
use cipher::BlockDecryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
for block in blocks.iter_mut() {
cipher.decrypt_block_mut(block);
}
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
#[bench]
pub fn $blocks_name(bh: &mut test::Bencher) {
use cipher::BlockDecryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
cipher.decrypt_blocks_mut(&mut blocks);
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
};
}

145
vendor/cipher/src/dev/stream.rs vendored Normal file
View File

@@ -0,0 +1,145 @@
//! Development-related functionality
/// Test core functionality of synchronous stream cipher
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! stream_cipher_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::generic_array::GenericArray;
use cipher::{blobby::Blob4Iterator, KeyIvInit, StreamCipher};
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() {
let [key, iv, pt, ct] = row.unwrap();
for chunk_n in 1..256 {
let mut mode = <$cipher>::new_from_slices(key, iv).unwrap();
let mut pt = pt.to_vec();
for chunk in pt.chunks_mut(chunk_n) {
mode.apply_keystream(chunk);
}
if pt != &ct[..] {
panic!(
"Failed main test №{}, chunk size: {}\n\
key:\t{:?}\n\
iv:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, chunk_n, key, iv, pt, ct,
);
}
}
}
}
};
}
/// Test stream synchronous stream cipher seeking capabilities
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! stream_cipher_seek_test {
($name:ident, $cipher:ty) => {
#[test]
fn $name() {
use cipher::generic_array::GenericArray;
use cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
fn get_cipher() -> $cipher {
<$cipher>::new(&Default::default(), &Default::default())
}
const MAX_SEEK: usize = 512;
let mut ct = [0u8; MAX_SEEK];
get_cipher().apply_keystream(&mut ct[..]);
for n in 0..MAX_SEEK {
let mut cipher = get_cipher();
assert_eq!(cipher.current_pos::<usize>(), 0);
cipher.seek(n);
assert_eq!(cipher.current_pos::<usize>(), n);
let mut buf = [0u8; MAX_SEEK];
cipher.apply_keystream(&mut buf[n..]);
assert_eq!(cipher.current_pos::<usize>(), MAX_SEEK);
assert_eq!(&buf[n..], &ct[n..]);
}
const MAX_CHUNK: usize = 128;
const MAX_LEN: usize = 1024;
let mut buf = [0u8; MAX_CHUNK];
let mut cipher = get_cipher();
assert_eq!(cipher.current_pos::<usize>(), 0);
cipher.apply_keystream(&mut []);
assert_eq!(cipher.current_pos::<usize>(), 0);
for n in 1..MAX_CHUNK {
assert_eq!(cipher.current_pos::<usize>(), 0);
for m in 1.. {
cipher.apply_keystream(&mut buf[..n]);
assert_eq!(cipher.current_pos::<usize>(), n * m);
if n * m > MAX_LEN {
break;
}
}
cipher.seek(0);
}
}
};
}
/// Create stream cipher benchmarks
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! stream_cipher_bench {
(
$cipher:ty;
$($name:ident $bs:expr;)*
) => {
$crate::stream_cipher_bench!(
Init: {
use $crate::KeyIvInit;
let key = test::black_box(Default::default());
let iv = test::black_box(Default::default());
<$cipher>::new(&key, &iv)
};
$($name $bs;)*
);
};
(
Key: $cipher:ty;
$($name:ident $bs:expr;)*
) => {
$crate::stream_cipher_bench!(
Init: {
use $crate::KeyInit;
let key = test::black_box(Default::default());
let iv = test::black_box(Default::default());
<$cipher>::new(&key, &iv)
};
$($name $bs;)*
);
};
(
Init: $init:expr;
$($name:ident $bs:expr;)*
) => {
$(
#[bench]
fn $name(b: &mut test::Bencher) {
use $crate::StreamCipher;
let mut cipher = $init;
let mut buf = vec![0; $bs];
b.iter(|| {
cipher.apply_keystream(&mut buf);
test::black_box(&buf);
});
b.bytes = $bs;
}
)*
};
}

43
vendor/cipher/src/errors.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
//! Error types.
use core::fmt;
/// This error is returned by the [`StreamCipher`][crate::stream::StreamCipher]
/// trait methods.
///
/// Usually it's used in cases when stream cipher has reached the end
/// of a keystream, but also can be used if lengths of provided input
/// and output buffers are not equal.
#[derive(Copy, Clone, Debug)]
pub struct StreamCipherError;
impl fmt::Display for StreamCipherError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("Loop Error")
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for StreamCipherError {}
/// The error type returned when a cipher position can not be represented
/// by the requested type.
#[derive(Copy, Clone, Debug)]
pub struct OverflowError;
impl fmt::Display for OverflowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("Overflow Error")
}
}
impl From<OverflowError> for StreamCipherError {
fn from(_: OverflowError) -> StreamCipherError {
StreamCipherError
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for OverflowError {}

60
vendor/cipher/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,60 @@
//! This crate defines a set of traits which describe the functionality of
//! [block ciphers][1], [block modes][2], and [stream ciphers][3].
//!
//! [1]: https://en.wikipedia.org/wiki/Block_cipher
//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
//! [3]: https://en.wikipedia.org/wiki/Stream_cipher
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
)]
#![warn(missing_docs, rust_2018_idioms)]
pub use crypto_common;
pub use inout;
#[cfg(all(feature = "block-padding", feature = "alloc"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "rand_core")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
pub use crypto_common::rand_core;
#[cfg(feature = "block-padding")]
#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
pub use inout::block_padding;
#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
pub use zeroize;
#[cfg(feature = "dev")]
pub use blobby;
mod block;
#[cfg(feature = "dev")]
mod dev;
mod errors;
mod stream;
mod stream_core;
mod stream_wrapper;
pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*};
pub use crypto_common::{
generic_array,
typenum::{self, consts},
AlgorithmName, Block, InnerIvInit, InvalidLength, Iv, IvSizeUser, Key, KeyInit, KeyIvInit,
KeySizeUser, ParBlocks, ParBlocksSizeUser,
};
/// Trait for loading current IV state.
pub trait IvState: IvSizeUser {
/// Returns current IV state.
fn iv_state(&self) -> Iv<Self>;
}

226
vendor/cipher/src/stream.rs vendored Normal file
View File

@@ -0,0 +1,226 @@
//! Traits which define functionality of stream ciphers.
//!
//! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers)
//! for ciphers implementation.
use crate::errors::{OverflowError, StreamCipherError};
use crate::stream_core::Counter;
use crate::{Block, BlockDecryptMut, BlockEncryptMut};
use inout::{InOutBuf, NotEqualError};
/// Marker trait for block-level asynchronous stream ciphers
pub trait AsyncStreamCipher: Sized {
/// Encrypt data using `InOutBuf`.
fn encrypt_inout(mut self, data: InOutBuf<'_, '_, u8>)
where
Self: BlockEncryptMut,
{
let (blocks, mut tail) = data.into_chunks();
self.encrypt_blocks_inout_mut(blocks);
let n = tail.len();
if n != 0 {
let mut block = Block::<Self>::default();
block[..n].copy_from_slice(tail.get_in());
self.encrypt_block_mut(&mut block);
tail.get_out().copy_from_slice(&block[..n]);
}
}
/// Decrypt data using `InOutBuf`.
fn decrypt_inout(mut self, data: InOutBuf<'_, '_, u8>)
where
Self: BlockDecryptMut,
{
let (blocks, mut tail) = data.into_chunks();
self.decrypt_blocks_inout_mut(blocks);
let n = tail.len();
if n != 0 {
let mut block = Block::<Self>::default();
block[..n].copy_from_slice(tail.get_in());
self.decrypt_block_mut(&mut block);
tail.get_out().copy_from_slice(&block[..n]);
}
}
/// Encrypt data in place.
fn encrypt(self, buf: &mut [u8])
where
Self: BlockEncryptMut,
{
self.encrypt_inout(buf.into());
}
/// Decrypt data in place.
fn decrypt(self, buf: &mut [u8])
where
Self: BlockDecryptMut,
{
self.decrypt_inout(buf.into());
}
/// Encrypt data from buffer to buffer.
fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError>
where
Self: BlockEncryptMut,
{
InOutBuf::new(in_buf, out_buf).map(|b| self.encrypt_inout(b))
}
/// Decrypt data from buffer to buffer.
fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError>
where
Self: BlockDecryptMut,
{
InOutBuf::new(in_buf, out_buf).map(|b| self.decrypt_inout(b))
}
}
/// Synchronous stream cipher core trait.
pub trait StreamCipher {
/// Apply keystream to `inout` data.
///
/// If end of the keystream will be achieved with the given data length,
/// method will return [`StreamCipherError`] without modifying provided `data`.
fn try_apply_keystream_inout(
&mut self,
buf: InOutBuf<'_, '_, u8>,
) -> Result<(), StreamCipherError>;
/// Apply keystream to data behind `buf`.
///
/// If end of the keystream will be achieved with the given data length,
/// method will return [`StreamCipherError`] without modifying provided `data`.
#[inline]
fn try_apply_keystream(&mut self, buf: &mut [u8]) -> Result<(), StreamCipherError> {
self.try_apply_keystream_inout(buf.into())
}
/// Apply keystream to `inout` data.
///
/// It will XOR generated keystream with the data behind `in` pointer
/// and will write result to `out` pointer.
///
/// # Panics
/// If end of the keystream will be reached with the given data length,
/// method will panic without modifying the provided `data`.
#[inline]
fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) {
self.try_apply_keystream_inout(buf).unwrap();
}
/// Apply keystream to data in-place.
///
/// It will XOR generated keystream with `data` and will write result
/// to the same buffer.
///
/// # Panics
/// If end of the keystream will be reached with the given data length,
/// method will panic without modifying the provided `data`.
#[inline]
fn apply_keystream(&mut self, buf: &mut [u8]) {
self.try_apply_keystream(buf).unwrap();
}
/// Apply keystream to data buffer-to-buffer.
///
/// It will XOR generated keystream with data from the `input` buffer
/// and will write result to the `output` buffer.
///
/// Returns [`StreamCipherError`] if provided `in_blocks` and `out_blocks`
/// have different lengths or if end of the keystream will be reached with
/// the given input data length.
#[inline]
fn apply_keystream_b2b(
&mut self,
input: &[u8],
output: &mut [u8],
) -> Result<(), StreamCipherError> {
InOutBuf::new(input, output)
.map_err(|_| StreamCipherError)
.and_then(|buf| self.try_apply_keystream_inout(buf))
}
}
/// Trait for seekable stream ciphers.
///
/// Methods of this trait are generic over the [`SeekNum`] trait, which is
/// implemented for primitive numeric types, i.e.: `i32`, `u32`, `u64`,
/// `u128`, and `usize`.
pub trait StreamCipherSeek {
/// Try to get current keystream position
///
/// Returns [`OverflowError`] if position can not be represented by type `T`
fn try_current_pos<T: SeekNum>(&self) -> Result<T, OverflowError>;
/// Try to seek to the given position
///
/// Returns [`StreamCipherError`] if provided position value is bigger than
/// keystream length.
fn try_seek<T: SeekNum>(&mut self, pos: T) -> Result<(), StreamCipherError>;
/// Get current keystream position
///
/// # Panics
/// If position can not be represented by type `T`
fn current_pos<T: SeekNum>(&self) -> T {
self.try_current_pos().unwrap()
}
/// Seek to the given position
///
/// # Panics
/// If provided position value is bigger than keystream length
fn seek<T: SeekNum>(&mut self, pos: T) {
self.try_seek(pos).unwrap()
}
}
impl<C: StreamCipher> StreamCipher for &mut C {
#[inline]
fn try_apply_keystream_inout(
&mut self,
buf: InOutBuf<'_, '_, u8>,
) -> Result<(), StreamCipherError> {
C::try_apply_keystream_inout(self, buf)
}
}
/// Trait implemented for numeric types which can be used with the
/// [`StreamCipherSeek`] trait.
///
/// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`.
/// It is not intended to be implemented in third-party crates.
pub trait SeekNum: Sized {
/// Try to get position for block number `block`, byte position inside
/// block `byte`, and block size `bs`.
fn from_block_byte<T: Counter>(block: T, byte: u8, bs: u8) -> Result<Self, OverflowError>;
/// Try to get block number and bytes position for given block size `bs`.
fn into_block_byte<T: Counter>(self, bs: u8) -> Result<(T, u8), OverflowError>;
}
macro_rules! impl_seek_num {
{$($t:ty )*} => {
$(
impl SeekNum for $t {
fn from_block_byte<T: Counter>(block: T, byte: u8, bs: u8) -> Result<Self, OverflowError> {
debug_assert!(byte < bs);
let mut block: Self = block.try_into().map_err(|_| OverflowError)?;
if byte != 0 {
block -= 1;
}
let pos = block.checked_mul(bs as Self).ok_or(OverflowError)? + (byte as Self);
Ok(pos)
}
fn into_block_byte<T: Counter>(self, bs: u8) -> Result<(T, u8), OverflowError> {
let bs = bs as Self;
let byte = self % bs;
let block = T::try_from(self/bs).map_err(|_| OverflowError)?;
Ok((block, byte as u8))
}
}
)*
};
}
impl_seek_num! { i32 u32 u64 u128 usize }

301
vendor/cipher/src/stream_core.rs vendored Normal file
View File

@@ -0,0 +1,301 @@
use crate::{ParBlocks, ParBlocksSizeUser, StreamCipherError};
use crypto_common::{
generic_array::{ArrayLength, GenericArray},
typenum::Unsigned,
Block, BlockSizeUser,
};
use inout::{InOut, InOutBuf};
/// Trait implemented by stream cipher backends.
pub trait StreamBackend: ParBlocksSizeUser {
/// Generate keystream block.
fn gen_ks_block(&mut self, block: &mut Block<Self>);
/// Generate keystream blocks in parallel.
#[inline(always)]
fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks<Self>) {
for block in blocks {
self.gen_ks_block(block);
}
}
/// Generate keystream blocks. Length of the buffer MUST be smaller
/// than `Self::ParBlocksSize`.
#[inline(always)]
fn gen_tail_blocks(&mut self, blocks: &mut [Block<Self>]) {
assert!(blocks.len() < Self::ParBlocksSize::USIZE);
for block in blocks {
self.gen_ks_block(block);
}
}
}
/// Trait for [`StreamBackend`] users.
///
/// This trait is used to define rank-2 closures.
pub trait StreamClosure: BlockSizeUser {
/// Execute closure with the provided stream cipher backend.
fn call<B: StreamBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
}
/// Block-level synchronous stream ciphers.
pub trait StreamCipherCore: BlockSizeUser + Sized {
/// Return number of remaining blocks before cipher wraps around.
///
/// Returns `None` if number of remaining blocks can not be computed
/// (e.g. in ciphers based on the sponge construction) or it's too big
/// to fit into `usize`.
fn remaining_blocks(&self) -> Option<usize>;
/// Process data using backend provided to the rank-2 closure.
fn process_with_backend(&mut self, f: impl StreamClosure<BlockSize = Self::BlockSize>);
/// Write keystream block.
///
/// WARNING: this method does not check number of remaining blocks!
#[inline]
fn write_keystream_block(&mut self, block: &mut Block<Self>) {
self.process_with_backend(WriteBlockCtx { block });
}
/// Write keystream blocks.
///
/// WARNING: this method does not check number of remaining blocks!
#[inline]
fn write_keystream_blocks(&mut self, blocks: &mut [Block<Self>]) {
self.process_with_backend(WriteBlocksCtx { blocks });
}
/// Apply keystream block.
///
/// WARNING: this method does not check number of remaining blocks!
#[inline]
fn apply_keystream_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
self.process_with_backend(ApplyBlockCtx { block });
}
/// Apply keystream blocks.
///
/// WARNING: this method does not check number of remaining blocks!
#[inline]
fn apply_keystream_blocks(&mut self, blocks: &mut [Block<Self>]) {
self.process_with_backend(ApplyBlocksCtx {
blocks: blocks.into(),
});
}
/// Apply keystream blocks.
///
/// WARNING: this method does not check number of remaining blocks!
#[inline]
fn apply_keystream_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.process_with_backend(ApplyBlocksCtx { blocks });
}
/// Try to apply keystream to data not divided into blocks.
///
/// Consumes cipher since it may consume final keystream block only
/// partially.
///
/// Returns an error if number of remaining blocks is not sufficient
/// for processing the input data.
#[inline]
fn try_apply_keystream_partial(
mut self,
mut buf: InOutBuf<'_, '_, u8>,
) -> Result<(), StreamCipherError> {
if let Some(rem) = self.remaining_blocks() {
let blocks = if buf.len() % Self::BlockSize::USIZE == 0 {
buf.len() % Self::BlockSize::USIZE
} else {
buf.len() % Self::BlockSize::USIZE + 1
};
if blocks > rem {
return Err(StreamCipherError);
}
}
if buf.len() > Self::BlockSize::USIZE {
let (blocks, tail) = buf.into_chunks();
self.apply_keystream_blocks_inout(blocks);
buf = tail;
}
let n = buf.len();
if n == 0 {
return Ok(());
}
let mut block = Block::<Self>::default();
block[..n].copy_from_slice(buf.get_in());
let t = InOutBuf::from_mut(&mut block);
self.apply_keystream_blocks_inout(t);
buf.get_out().copy_from_slice(&block[..n]);
Ok(())
}
/// Try to apply keystream to data not divided into blocks.
///
/// Consumes cipher since it may consume final keystream block only
/// partially.
///
/// # Panics
/// If number of remaining blocks is not sufficient for processing the
/// input data.
#[inline]
fn apply_keystream_partial(self, buf: InOutBuf<'_, '_, u8>) {
self.try_apply_keystream_partial(buf).unwrap()
}
}
// note: unfortunately, currently we can not write blanket impls of
// `BlockEncryptMut` and `BlockDecryptMut` for `T: StreamCipherCore`
// since it requires mutually exclusive traits, see:
// https://github.com/rust-lang/rfcs/issues/1053
/// Counter type usable with [`StreamCipherCore`].
///
/// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`.
/// It's not intended to be implemented in third-party crates, but doing so
/// is not forbidden.
pub trait Counter:
TryFrom<i32>
+ TryFrom<u32>
+ TryFrom<u64>
+ TryFrom<u128>
+ TryFrom<usize>
+ TryInto<i32>
+ TryInto<u32>
+ TryInto<u64>
+ TryInto<u128>
+ TryInto<usize>
{
}
/// Block-level seeking trait for stream ciphers.
pub trait StreamCipherSeekCore: StreamCipherCore {
/// Counter type used inside stream cipher.
type Counter: Counter;
/// Get current block position.
fn get_block_pos(&self) -> Self::Counter;
/// Set block position.
fn set_block_pos(&mut self, pos: Self::Counter);
}
macro_rules! impl_counter {
{$($t:ty )*} => {
$( impl Counter for $t { } )*
};
}
impl_counter! { u32 u64 u128 }
/// Partition buffer into 2 parts: buffer of arrays and tail.
///
/// In case if `N` is less or equal to 1, buffer of arrays has length
/// of zero and tail is equal to `self`.
#[inline]
fn into_chunks<T, N: ArrayLength<T>>(buf: &mut [T]) -> (&mut [GenericArray<T, N>], &mut [T]) {
use core::slice;
if N::USIZE <= 1 {
return (&mut [], buf);
}
let chunks_len = buf.len() / N::USIZE;
let tail_pos = N::USIZE * chunks_len;
let tail_len = buf.len() - tail_pos;
unsafe {
let ptr = buf.as_mut_ptr();
let chunks = slice::from_raw_parts_mut(ptr as *mut GenericArray<T, N>, chunks_len);
let tail = slice::from_raw_parts_mut(ptr.add(tail_pos), tail_len);
(chunks, tail)
}
}
struct WriteBlockCtx<'a, BS: ArrayLength<u8>> {
block: &'a mut Block<Self>,
}
impl<'a, BS: ArrayLength<u8>> BlockSizeUser for WriteBlockCtx<'a, BS> {
type BlockSize = BS;
}
impl<'a, BS: ArrayLength<u8>> StreamClosure for WriteBlockCtx<'a, BS> {
#[inline(always)]
fn call<B: StreamBackend<BlockSize = BS>>(self, backend: &mut B) {
backend.gen_ks_block(self.block);
}
}
struct WriteBlocksCtx<'a, BS: ArrayLength<u8>> {
blocks: &'a mut [Block<Self>],
}
impl<'a, BS: ArrayLength<u8>> BlockSizeUser for WriteBlocksCtx<'a, BS> {
type BlockSize = BS;
}
impl<'a, BS: ArrayLength<u8>> StreamClosure for WriteBlocksCtx<'a, BS> {
#[inline(always)]
fn call<B: StreamBackend<BlockSize = BS>>(self, backend: &mut B) {
if B::ParBlocksSize::USIZE > 1 {
let (chunks, tail) = into_chunks::<_, B::ParBlocksSize>(self.blocks);
for chunk in chunks {
backend.gen_par_ks_blocks(chunk);
}
backend.gen_tail_blocks(tail);
} else {
for block in self.blocks {
backend.gen_ks_block(block);
}
}
}
}
struct ApplyBlockCtx<'inp, 'out, BS: ArrayLength<u8>> {
block: InOut<'inp, 'out, Block<Self>>,
}
impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for ApplyBlockCtx<'inp, 'out, BS> {
type BlockSize = BS;
}
impl<'inp, 'out, BS: ArrayLength<u8>> StreamClosure for ApplyBlockCtx<'inp, 'out, BS> {
#[inline(always)]
fn call<B: StreamBackend<BlockSize = BS>>(mut self, backend: &mut B) {
let mut t = Default::default();
backend.gen_ks_block(&mut t);
self.block.xor_in2out(&t);
}
}
struct ApplyBlocksCtx<'inp, 'out, BS: ArrayLength<u8>> {
blocks: InOutBuf<'inp, 'out, Block<Self>>,
}
impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for ApplyBlocksCtx<'inp, 'out, BS> {
type BlockSize = BS;
}
impl<'inp, 'out, BS: ArrayLength<u8>> StreamClosure for ApplyBlocksCtx<'inp, 'out, BS> {
#[inline(always)]
#[allow(clippy::needless_range_loop)]
fn call<B: StreamBackend<BlockSize = BS>>(self, backend: &mut B) {
if B::ParBlocksSize::USIZE > 1 {
let (chunks, mut tail) = self.blocks.into_chunks::<B::ParBlocksSize>();
for mut chunk in chunks {
let mut tmp = Default::default();
backend.gen_par_ks_blocks(&mut tmp);
chunk.xor_in2out(&tmp);
}
let n = tail.len();
let mut buf = GenericArray::<_, B::ParBlocksSize>::default();
let ks = &mut buf[..n];
backend.gen_tail_blocks(ks);
for i in 0..n {
tail.get(i).xor_in2out(&ks[i]);
}
} else {
for mut block in self.blocks {
let mut t = Default::default();
backend.gen_ks_block(&mut t);
block.xor_in2out(&t);
}
}
}
}

242
vendor/cipher/src/stream_wrapper.rs vendored Normal file
View File

@@ -0,0 +1,242 @@
use crate::{
errors::StreamCipherError, Block, OverflowError, SeekNum, StreamCipher, StreamCipherCore,
StreamCipherSeek, StreamCipherSeekCore,
};
use crypto_common::{
typenum::{IsLess, Le, NonZero, Unsigned, U256},
BlockSizeUser, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser,
};
use inout::InOutBuf;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
/// Wrapper around [`StreamCipherCore`] implementations.
///
/// It handles data buffering and implements the slice-based traits.
#[derive(Clone, Default)]
pub struct StreamCipherCoreWrapper<T: BlockSizeUser>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
core: T,
buffer: Block<T>,
pos: u8,
}
impl<T: StreamCipherCore> StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
/// Return reference to the core type.
pub fn get_core(&self) -> &T {
&self.core
}
/// Return reference to the core type.
pub fn from_core(core: T) -> Self {
Self {
core,
buffer: Default::default(),
pos: 0,
}
}
/// Return current cursor position.
#[inline]
fn get_pos(&self) -> usize {
let pos = self.pos as usize;
if T::BlockSize::USIZE == 0 {
panic!("Block size can not be equal to zero");
}
if pos >= T::BlockSize::USIZE {
debug_assert!(false);
// SAFETY: `pos` is set only to values smaller than block size
unsafe { core::hint::unreachable_unchecked() }
}
self.pos as usize
}
/// Return size of the internal buffer in bytes.
#[inline]
fn size(&self) -> usize {
T::BlockSize::USIZE
}
#[inline]
fn set_pos_unchecked(&mut self, pos: usize) {
debug_assert!(pos < T::BlockSize::USIZE);
self.pos = pos as u8;
}
/// Return number of remaining bytes in the internal buffer.
#[inline]
fn remaining(&self) -> usize {
self.size() - self.get_pos()
}
fn check_remaining(&self, dlen: usize) -> Result<(), StreamCipherError> {
let rem_blocks = match self.core.remaining_blocks() {
Some(v) => v,
None => return Ok(()),
};
let bytes = if self.pos == 0 {
dlen
} else {
let rem = self.remaining();
if dlen > rem {
dlen - rem
} else {
return Ok(());
}
};
let bs = T::BlockSize::USIZE;
let blocks = if bytes % bs == 0 {
bytes / bs
} else {
bytes / bs + 1
};
if blocks > rem_blocks {
Err(StreamCipherError)
} else {
Ok(())
}
}
}
impl<T: StreamCipherCore> StreamCipher for StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn try_apply_keystream_inout(
&mut self,
mut data: InOutBuf<'_, '_, u8>,
) -> Result<(), StreamCipherError> {
self.check_remaining(data.len())?;
let pos = self.get_pos();
if pos != 0 {
let rem = &self.buffer[pos..];
let n = data.len();
if n < rem.len() {
data.xor_in2out(&rem[..n]);
self.set_pos_unchecked(pos + n);
return Ok(());
}
let (mut left, right) = data.split_at(rem.len());
data = right;
left.xor_in2out(rem);
}
let (blocks, mut leftover) = data.into_chunks();
self.core.apply_keystream_blocks_inout(blocks);
let n = leftover.len();
if n != 0 {
self.core.write_keystream_block(&mut self.buffer);
leftover.xor_in2out(&self.buffer[..n]);
}
self.set_pos_unchecked(n);
Ok(())
}
}
impl<T: StreamCipherSeekCore> StreamCipherSeek for StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
fn try_current_pos<SN: SeekNum>(&self) -> Result<SN, OverflowError> {
let Self { core, pos, .. } = self;
SN::from_block_byte(core.get_block_pos(), *pos, T::BlockSize::U8)
}
fn try_seek<SN: SeekNum>(&mut self, new_pos: SN) -> Result<(), StreamCipherError> {
let Self { core, buffer, pos } = self;
let (block_pos, byte_pos) = new_pos.into_block_byte(T::BlockSize::U8)?;
core.set_block_pos(block_pos);
if byte_pos != 0 {
self.core.write_keystream_block(buffer);
}
*pos = byte_pos;
Ok(())
}
}
// Note: ideally we would only implement the InitInner trait and everything
// else would be handled by blanket impls, but unfortunately it will
// not work properly without mutually exclusive traits, see:
// https://github.com/rust-lang/rfcs/issues/1053
impl<T: KeySizeUser + BlockSizeUser> KeySizeUser for StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
type KeySize = T::KeySize;
}
impl<T: IvSizeUser + BlockSizeUser> IvSizeUser for StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
type IvSize = T::IvSize;
}
impl<T: KeyIvInit + BlockSizeUser> KeyIvInit for StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn new(key: &Key<Self>, iv: &Iv<Self>) -> Self {
Self {
core: T::new(key, iv),
buffer: Default::default(),
pos: 0,
}
}
}
impl<T: KeyInit + BlockSizeUser> KeyInit for StreamCipherCoreWrapper<T>
where
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn new(key: &Key<Self>) -> Self {
Self {
core: T::new(key),
buffer: Default::default(),
pos: 0,
}
}
}
#[cfg(feature = "zeroize")]
impl<T> Drop for StreamCipherCoreWrapper<T>
where
T: BlockSizeUser,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.buffer.zeroize();
self.pos.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl<T> ZeroizeOnDrop for StreamCipherCoreWrapper<T>
where
T: BlockSizeUser + ZeroizeOnDrop,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
}