cipher/
block.rs

1//! Traits used to define functionality of [block ciphers][1] and [modes of operation][2].
2//!
3//! # About block ciphers
4//!
5//! Block ciphers are keyed, deterministic permutations of a fixed-sized input
6//! "block" providing a reversible transformation to/from an encrypted output.
7//! They are one of the fundamental structural components of [symmetric cryptography][3].
8//!
9//! [1]: https://en.wikipedia.org/wiki/Block_cipher
10//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
11//! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
12
13use crate::{ParBlocks, ParBlocksSizeUser};
14#[cfg(all(feature = "block-padding", feature = "alloc"))]
15use alloc::{vec, vec::Vec};
16#[cfg(feature = "block-padding")]
17use inout::{
18    block_padding::{Padding, UnpadError},
19    InOutBufReserved, PadError,
20};
21use inout::{InOut, InOutBuf, NotEqualError};
22
23pub use crypto_common::{generic_array::ArrayLength, typenum::Unsigned, Block, BlockSizeUser};
24
25/// Marker trait for block ciphers.
26pub trait BlockCipher: BlockSizeUser {}
27
28/// Trait implemented by block cipher encryption and decryption backends.
29pub trait BlockBackend: ParBlocksSizeUser {
30    /// Process single inout block.
31    fn proc_block(&mut self, block: InOut<'_, '_, Block<Self>>);
32
33    /// Process inout blocks in parallel.
34    #[inline(always)]
35    fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks<Self>>) {
36        for i in 0..Self::ParBlocksSize::USIZE {
37            self.proc_block(blocks.get(i));
38        }
39    }
40
41    /// Process buffer of inout blocks. Length of the buffer MUST be smaller
42    /// than `Self::ParBlocksSize`.
43    #[inline(always)]
44    fn proc_tail_blocks(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
45        assert!(blocks.len() < Self::ParBlocksSize::USIZE);
46        for block in blocks {
47            self.proc_block(block);
48        }
49    }
50
51    /// Process single block in-place.
52    #[inline(always)]
53    fn proc_block_inplace(&mut self, block: &mut Block<Self>) {
54        self.proc_block(block.into());
55    }
56
57    /// Process blocks in parallel in-place.
58    #[inline(always)]
59    fn proc_par_blocks_inplace(&mut self, blocks: &mut ParBlocks<Self>) {
60        self.proc_par_blocks(blocks.into());
61    }
62
63    /// Process buffer of blocks in-place. Length of the buffer MUST be smaller
64    /// than `Self::ParBlocksSize`.
65    #[inline(always)]
66    fn proc_tail_blocks_inplace(&mut self, blocks: &mut [Block<Self>]) {
67        self.proc_tail_blocks(blocks.into());
68    }
69}
70
71/// Trait for [`BlockBackend`] users.
72///
73/// This trait is used to define rank-2 closures.
74pub trait BlockClosure: BlockSizeUser {
75    /// Execute closure with the provided block cipher backend.
76    fn call<B: BlockBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
77}
78
79/// Encrypt-only functionality for block ciphers.
80pub trait BlockEncrypt: BlockSizeUser + Sized {
81    /// Encrypt data using backend provided to the rank-2 closure.
82    fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
83
84    /// Encrypt single `inout` block.
85    #[inline]
86    fn encrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
87        self.encrypt_with_backend(BlockCtx { block });
88    }
89
90    /// Encrypt `inout` blocks.
91    #[inline]
92    fn encrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
93        self.encrypt_with_backend(BlocksCtx { blocks });
94    }
95
96    /// Encrypt single block in-place.
97    #[inline]
98    fn encrypt_block(&self, block: &mut Block<Self>) {
99        let block = block.into();
100        self.encrypt_with_backend(BlockCtx { block });
101    }
102
103    /// Encrypt `in_block` and write result to `out_block`.
104    #[inline]
105    fn encrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
106        let block = (in_block, out_block).into();
107        self.encrypt_with_backend(BlockCtx { block });
108    }
109
110    /// Encrypt blocks in-place.
111    #[inline]
112    fn encrypt_blocks(&self, blocks: &mut [Block<Self>]) {
113        let blocks = blocks.into();
114        self.encrypt_with_backend(BlocksCtx { blocks });
115    }
116
117    /// Encrypt blocks buffer-to-buffer.
118    ///
119    /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
120    /// have different lengths.
121    #[inline]
122    fn encrypt_blocks_b2b(
123        &self,
124        in_blocks: &[Block<Self>],
125        out_blocks: &mut [Block<Self>],
126    ) -> Result<(), NotEqualError> {
127        InOutBuf::new(in_blocks, out_blocks)
128            .map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
129    }
130
131    /// Pad input and encrypt. Returns resulting ciphertext slice.
132    ///
133    /// Returns [`PadError`] if length of output buffer is not sufficient.
134    #[cfg(feature = "block-padding")]
135    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
136    #[inline]
137    fn encrypt_padded_inout<'inp, 'out, P: Padding<Self::BlockSize>>(
138        &self,
139        data: InOutBufReserved<'inp, 'out, u8>,
140    ) -> Result<&'out [u8], PadError> {
141        let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
142        self.encrypt_blocks_inout(buf.get_blocks());
143        if let Some(block) = buf.get_tail_block() {
144            self.encrypt_block_inout(block);
145        }
146        Ok(buf.into_out())
147    }
148
149    /// Pad input and encrypt in-place. Returns resulting ciphertext slice.
150    ///
151    /// Returns [`PadError`] if length of output buffer is not sufficient.
152    #[cfg(feature = "block-padding")]
153    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
154    #[inline]
155    fn encrypt_padded<'a, P: Padding<Self::BlockSize>>(
156        &self,
157        buf: &'a mut [u8],
158        msg_len: usize,
159    ) -> Result<&'a [u8], PadError> {
160        let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
161        self.encrypt_padded_inout::<P>(buf)
162    }
163
164    /// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice.
165    ///
166    /// Returns [`PadError`] if length of output buffer is not sufficient.
167    #[cfg(feature = "block-padding")]
168    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
169    #[inline]
170    fn encrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
171        &self,
172        msg: &[u8],
173        out_buf: &'a mut [u8],
174    ) -> Result<&'a [u8], PadError> {
175        let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
176        self.encrypt_padded_inout::<P>(buf)
177    }
178
179    /// Pad input and encrypt into a newly allocated Vec. Returns resulting ciphertext Vec.
180    #[cfg(all(feature = "block-padding", feature = "alloc"))]
181    #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))]
182    #[inline]
183    fn encrypt_padded_vec<P: Padding<Self::BlockSize>>(&self, msg: &[u8]) -> Vec<u8> {
184        let mut out = allocate_out_vec::<Self>(msg.len());
185        let len = self
186            .encrypt_padded_b2b::<P>(msg, &mut out)
187            .expect("enough space for encrypting is allocated")
188            .len();
189        out.truncate(len);
190        out
191    }
192}
193
194/// Decrypt-only functionality for block ciphers.
195pub trait BlockDecrypt: BlockSizeUser {
196    /// Decrypt data using backend provided to the rank-2 closure.
197    fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
198
199    /// Decrypt single `inout` block.
200    #[inline]
201    fn decrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
202        self.decrypt_with_backend(BlockCtx { block });
203    }
204
205    /// Decrypt `inout` blocks.
206    #[inline]
207    fn decrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
208        self.decrypt_with_backend(BlocksCtx { blocks });
209    }
210
211    /// Decrypt single block in-place.
212    #[inline]
213    fn decrypt_block(&self, block: &mut Block<Self>) {
214        let block = block.into();
215        self.decrypt_with_backend(BlockCtx { block });
216    }
217
218    /// Decrypt `in_block` and write result to `out_block`.
219    #[inline]
220    fn decrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
221        let block = (in_block, out_block).into();
222        self.decrypt_with_backend(BlockCtx { block });
223    }
224
225    /// Decrypt blocks in-place.
226    #[inline]
227    fn decrypt_blocks(&self, blocks: &mut [Block<Self>]) {
228        let blocks = blocks.into();
229        self.decrypt_with_backend(BlocksCtx { blocks });
230    }
231
232    /// Decrypt blocks buffer-to-buffer.
233    ///
234    /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
235    /// have different lengths.
236    #[inline]
237    fn decrypt_blocks_b2b(
238        &self,
239        in_blocks: &[Block<Self>],
240        out_blocks: &mut [Block<Self>],
241    ) -> Result<(), NotEqualError> {
242        InOutBuf::new(in_blocks, out_blocks)
243            .map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
244    }
245
246    /// Decrypt input and unpad it. Returns resulting ciphertext slice.
247    ///
248    /// Returns [`UnpadError`] if padding is malformed or if input length is
249    /// not multiple of `Self::BlockSize`.
250    #[cfg(feature = "block-padding")]
251    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
252    #[inline]
253    fn decrypt_padded_inout<'inp, 'out, P: Padding<Self::BlockSize>>(
254        &self,
255        data: InOutBuf<'inp, 'out, u8>,
256    ) -> Result<&'out [u8], UnpadError> {
257        let (mut blocks, tail) = data.into_chunks();
258        if !tail.is_empty() {
259            return Err(UnpadError);
260        }
261        self.decrypt_blocks_inout(blocks.reborrow());
262        P::unpad_blocks(blocks.into_out())
263    }
264
265    /// Decrypt input and unpad it in-place. Returns resulting ciphertext slice.
266    ///
267    /// Returns [`UnpadError`] if padding is malformed or if input length is
268    /// not multiple of `Self::BlockSize`.
269    #[cfg(feature = "block-padding")]
270    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
271    #[inline]
272    fn decrypt_padded<'a, P: Padding<Self::BlockSize>>(
273        &self,
274        buf: &'a mut [u8],
275    ) -> Result<&'a [u8], UnpadError> {
276        self.decrypt_padded_inout::<P>(buf.into())
277    }
278
279    /// Decrypt input and unpad it buffer-to-buffer. Returns resulting
280    /// ciphertext slice.
281    ///
282    /// Returns [`UnpadError`] if padding is malformed or if input length is
283    /// not multiple of `Self::BlockSize`.
284    #[cfg(feature = "block-padding")]
285    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
286    #[inline]
287    fn decrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
288        &self,
289        in_buf: &[u8],
290        out_buf: &'a mut [u8],
291    ) -> Result<&'a [u8], UnpadError> {
292        if out_buf.len() < in_buf.len() {
293            return Err(UnpadError);
294        }
295        let n = in_buf.len();
296        // note: `new` always returns `Ok` here
297        let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?;
298        self.decrypt_padded_inout::<P>(buf)
299    }
300
301    /// Decrypt input and unpad it in a newly allocated Vec. Returns resulting
302    /// ciphertext Vec.
303    ///
304    /// Returns [`UnpadError`] if padding is malformed or if input length is
305    /// not multiple of `Self::BlockSize`.
306    #[cfg(all(feature = "block-padding", feature = "alloc"))]
307    #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))]
308    #[inline]
309    fn decrypt_padded_vec<P: Padding<Self::BlockSize>>(
310        &self,
311        buf: &[u8],
312    ) -> Result<Vec<u8>, UnpadError> {
313        let mut out = vec![0; buf.len()];
314        let len = self.decrypt_padded_b2b::<P>(buf, &mut out)?.len();
315        out.truncate(len);
316        Ok(out)
317    }
318}
319
320/// Encrypt-only functionality for block ciphers and modes with mutable access to `self`.
321///
322/// The main use case for this trait is blocks modes, but it also can be used
323/// for hardware cryptographic engines which require `&mut self` access to an
324/// underlying hardware peripheral.
325pub trait BlockEncryptMut: BlockSizeUser + Sized {
326    /// Encrypt data using backend provided to the rank-2 closure.
327    fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
328
329    /// Encrypt single `inout` block.
330    #[inline]
331    fn encrypt_block_inout_mut(&mut self, block: InOut<'_, '_, Block<Self>>) {
332        self.encrypt_with_backend_mut(BlockCtx { block });
333    }
334
335    /// Encrypt `inout` blocks.
336    #[inline]
337    fn encrypt_blocks_inout_mut(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
338        self.encrypt_with_backend_mut(BlocksCtx { blocks });
339    }
340
341    /// Encrypt single block in-place.
342    #[inline]
343    fn encrypt_block_mut(&mut self, block: &mut Block<Self>) {
344        let block = block.into();
345        self.encrypt_with_backend_mut(BlockCtx { block });
346    }
347
348    /// Encrypt `in_block` and write result to `out_block`.
349    #[inline]
350    fn encrypt_block_b2b_mut(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
351        let block = (in_block, out_block).into();
352        self.encrypt_with_backend_mut(BlockCtx { block });
353    }
354
355    /// Encrypt blocks in-place.
356    #[inline]
357    fn encrypt_blocks_mut(&mut self, blocks: &mut [Block<Self>]) {
358        let blocks = blocks.into();
359        self.encrypt_with_backend_mut(BlocksCtx { blocks });
360    }
361
362    /// Encrypt blocks buffer-to-buffer.
363    ///
364    /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
365    /// have different lengths.
366    #[inline]
367    fn encrypt_blocks_b2b_mut(
368        &mut self,
369        in_blocks: &[Block<Self>],
370        out_blocks: &mut [Block<Self>],
371    ) -> Result<(), NotEqualError> {
372        InOutBuf::new(in_blocks, out_blocks)
373            .map(|blocks| self.encrypt_with_backend_mut(BlocksCtx { blocks }))
374    }
375
376    /// Pad input and encrypt. Returns resulting ciphertext slice.
377    ///
378    /// Returns [`PadError`] if length of output buffer is not sufficient.
379    #[cfg(feature = "block-padding")]
380    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
381    #[inline]
382    fn encrypt_padded_inout_mut<'inp, 'out, P: Padding<Self::BlockSize>>(
383        mut self,
384        data: InOutBufReserved<'inp, 'out, u8>,
385    ) -> Result<&'out [u8], PadError> {
386        let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
387        self.encrypt_blocks_inout_mut(buf.get_blocks());
388        if let Some(block) = buf.get_tail_block() {
389            self.encrypt_block_inout_mut(block);
390        }
391        Ok(buf.into_out())
392    }
393
394    /// Pad input and encrypt in-place. Returns resulting ciphertext slice.
395    ///
396    /// Returns [`PadError`] if length of output buffer is not sufficient.
397    #[cfg(feature = "block-padding")]
398    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
399    #[inline]
400    fn encrypt_padded_mut<P: Padding<Self::BlockSize>>(
401        self,
402        buf: &mut [u8],
403        msg_len: usize,
404    ) -> Result<&[u8], PadError> {
405        let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
406        self.encrypt_padded_inout_mut::<P>(buf)
407    }
408
409    /// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice.
410    ///
411    /// Returns [`PadError`] if length of output buffer is not sufficient.
412    #[cfg(feature = "block-padding")]
413    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
414    #[inline]
415    fn encrypt_padded_b2b_mut<'a, P: Padding<Self::BlockSize>>(
416        self,
417        msg: &[u8],
418        out_buf: &'a mut [u8],
419    ) -> Result<&'a [u8], PadError> {
420        let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
421        self.encrypt_padded_inout_mut::<P>(buf)
422    }
423
424    /// Pad input and encrypt into a newly allocated Vec. Returns resulting ciphertext Vec.
425    #[cfg(all(feature = "block-padding", feature = "alloc"))]
426    #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))]
427    #[inline]
428    fn encrypt_padded_vec_mut<P: Padding<Self::BlockSize>>(self, msg: &[u8]) -> Vec<u8> {
429        let mut out = allocate_out_vec::<Self>(msg.len());
430        let len = self
431            .encrypt_padded_b2b_mut::<P>(msg, &mut out)
432            .expect("enough space for encrypting is allocated")
433            .len();
434        out.truncate(len);
435        out
436    }
437}
438
439/// Decrypt-only functionality for block ciphers and modes with mutable access to `self`.
440///
441/// The main use case for this trait is blocks modes, but it also can be used
442/// for hardware cryptographic engines which require `&mut self` access to an
443/// underlying hardware peripheral.
444pub trait BlockDecryptMut: BlockSizeUser + Sized {
445    /// Decrypt data using backend provided to the rank-2 closure.
446    fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>);
447
448    /// Decrypt single `inout` block.
449    #[inline]
450    fn decrypt_block_inout_mut(&mut self, block: InOut<'_, '_, Block<Self>>) {
451        self.decrypt_with_backend_mut(BlockCtx { block });
452    }
453
454    /// Decrypt `inout` blocks.
455    #[inline]
456    fn decrypt_blocks_inout_mut(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
457        self.decrypt_with_backend_mut(BlocksCtx { blocks });
458    }
459
460    /// Decrypt single block in-place.
461    #[inline]
462    fn decrypt_block_mut(&mut self, block: &mut Block<Self>) {
463        let block = block.into();
464        self.decrypt_with_backend_mut(BlockCtx { block });
465    }
466
467    /// Decrypt `in_block` and write result to `out_block`.
468    #[inline]
469    fn decrypt_block_b2b_mut(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
470        let block = (in_block, out_block).into();
471        self.decrypt_with_backend_mut(BlockCtx { block });
472    }
473
474    /// Decrypt blocks in-place.
475    #[inline]
476    fn decrypt_blocks_mut(&mut self, blocks: &mut [Block<Self>]) {
477        let blocks = blocks.into();
478        self.decrypt_with_backend_mut(BlocksCtx { blocks });
479    }
480
481    /// Decrypt blocks buffer-to-buffer.
482    ///
483    /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
484    /// have different lengths.
485    #[inline]
486    fn decrypt_blocks_b2b_mut(
487        &mut self,
488        in_blocks: &[Block<Self>],
489        out_blocks: &mut [Block<Self>],
490    ) -> Result<(), NotEqualError> {
491        InOutBuf::new(in_blocks, out_blocks)
492            .map(|blocks| self.decrypt_with_backend_mut(BlocksCtx { blocks }))
493    }
494
495    /// Decrypt input and unpad it. Returns resulting ciphertext slice.
496    ///
497    /// Returns [`UnpadError`] if padding is malformed or if input length is
498    /// not multiple of `Self::BlockSize`.
499    #[cfg(feature = "block-padding")]
500    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
501    #[inline]
502    fn decrypt_padded_inout_mut<'inp, 'out, P: Padding<Self::BlockSize>>(
503        mut self,
504        data: InOutBuf<'inp, 'out, u8>,
505    ) -> Result<&'out [u8], UnpadError> {
506        let (mut blocks, tail) = data.into_chunks();
507        if !tail.is_empty() {
508            return Err(UnpadError);
509        }
510        self.decrypt_blocks_inout_mut(blocks.reborrow());
511        P::unpad_blocks(blocks.into_out())
512    }
513
514    /// Decrypt input and unpad it in-place. Returns resulting ciphertext slice.
515    ///
516    /// Returns [`UnpadError`] if padding is malformed or if input length is
517    /// not multiple of `Self::BlockSize`.
518    #[cfg(feature = "block-padding")]
519    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
520    #[inline]
521    fn decrypt_padded_mut<P: Padding<Self::BlockSize>>(
522        self,
523        buf: &mut [u8],
524    ) -> Result<&[u8], UnpadError> {
525        self.decrypt_padded_inout_mut::<P>(buf.into())
526    }
527
528    /// Decrypt input and unpad it buffer-to-buffer. Returns resulting
529    /// ciphertext slice.
530    ///
531    /// Returns [`UnpadError`] if padding is malformed or if input length is
532    /// not multiple of `Self::BlockSize`.
533    #[cfg(feature = "block-padding")]
534    #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))]
535    #[inline]
536    fn decrypt_padded_b2b_mut<'a, P: Padding<Self::BlockSize>>(
537        self,
538        in_buf: &[u8],
539        out_buf: &'a mut [u8],
540    ) -> Result<&'a [u8], UnpadError> {
541        if out_buf.len() < in_buf.len() {
542            return Err(UnpadError);
543        }
544        let n = in_buf.len();
545        // note: `new` always returns `Ok` here
546        let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?;
547        self.decrypt_padded_inout_mut::<P>(buf)
548    }
549
550    /// Decrypt input and unpad it in a newly allocated Vec. Returns resulting
551    /// ciphertext Vec.
552    ///
553    /// Returns [`UnpadError`] if padding is malformed or if input length is
554    /// not multiple of `Self::BlockSize`.
555    #[cfg(all(feature = "block-padding", feature = "alloc"))]
556    #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))]
557    #[inline]
558    fn decrypt_padded_vec_mut<P: Padding<Self::BlockSize>>(
559        self,
560        buf: &[u8],
561    ) -> Result<Vec<u8>, UnpadError> {
562        let mut out = vec![0; buf.len()];
563        let len = self.decrypt_padded_b2b_mut::<P>(buf, &mut out)?.len();
564        out.truncate(len);
565        Ok(out)
566    }
567}
568
569impl<Alg: BlockEncrypt> BlockEncryptMut for Alg {
570    fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
571        self.encrypt_with_backend(f);
572    }
573}
574
575impl<Alg: BlockDecrypt> BlockDecryptMut for Alg {
576    fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
577        self.decrypt_with_backend(f);
578    }
579}
580
581impl<Alg: BlockCipher> BlockCipher for &Alg {}
582
583impl<Alg: BlockEncrypt> BlockEncrypt for &Alg {
584    fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
585        Alg::encrypt_with_backend(self, f);
586    }
587}
588
589impl<Alg: BlockDecrypt> BlockDecrypt for &Alg {
590    fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = Self::BlockSize>) {
591        Alg::decrypt_with_backend(self, f);
592    }
593}
594
595/// Closure used in methods which operate over separate blocks.
596struct BlockCtx<'inp, 'out, BS: ArrayLength<u8>> {
597    block: InOut<'inp, 'out, Block<Self>>,
598}
599
600impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for BlockCtx<'inp, 'out, BS> {
601    type BlockSize = BS;
602}
603
604impl<'inp, 'out, BS: ArrayLength<u8>> BlockClosure for BlockCtx<'inp, 'out, BS> {
605    #[inline(always)]
606    fn call<B: BlockBackend<BlockSize = BS>>(self, backend: &mut B) {
607        backend.proc_block(self.block);
608    }
609}
610
611/// Closure used in methods which operate over slice of blocks.
612struct BlocksCtx<'inp, 'out, BS: ArrayLength<u8>> {
613    blocks: InOutBuf<'inp, 'out, Block<Self>>,
614}
615
616impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for BlocksCtx<'inp, 'out, BS> {
617    type BlockSize = BS;
618}
619
620impl<'inp, 'out, BS: ArrayLength<u8>> BlockClosure for BlocksCtx<'inp, 'out, BS> {
621    #[inline(always)]
622    fn call<B: BlockBackend<BlockSize = BS>>(self, backend: &mut B) {
623        if B::ParBlocksSize::USIZE > 1 {
624            let (chunks, tail) = self.blocks.into_chunks();
625            for chunk in chunks {
626                backend.proc_par_blocks(chunk);
627            }
628            backend.proc_tail_blocks(tail);
629        } else {
630            for block in self.blocks {
631                backend.proc_block(block);
632            }
633        }
634    }
635}
636
637#[cfg(all(feature = "block-padding", feature = "alloc"))]
638fn allocate_out_vec<BS: BlockSizeUser>(len: usize) -> Vec<u8> {
639    let bs = BS::BlockSize::USIZE;
640    vec![0; bs * (len / bs + 1)]
641}
642
643/// Implement simple block backend
644#[macro_export]
645macro_rules! impl_simple_block_encdec {
646    (
647        <$($N:ident$(:$b0:ident$(+$b:ident)*)?),*>
648        $cipher:ident, $block_size:ty, $state:ident, $block:ident,
649        encrypt: $enc_block:block
650        decrypt: $dec_block:block
651    ) => {
652        impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockSizeUser for $cipher<$($N),*> {
653            type BlockSize = $block_size;
654        }
655
656        impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockEncrypt for $cipher<$($N),*> {
657            fn encrypt_with_backend(&self, f: impl $crate::BlockClosure<BlockSize = $block_size>) {
658                struct EncBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>);
659
660                impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for EncBack<'a, $($N),*> {
661                    type BlockSize = $block_size;
662                }
663
664                impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for EncBack<'a, $($N),*> {
665                    type ParBlocksSize = $crate::consts::U1;
666                }
667
668                impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for EncBack<'a, $($N),*> {
669                    #[inline(always)]
670                    fn proc_block(
671                        &mut self,
672                        mut $block: $crate::inout::InOut<'_, '_, $crate::Block<Self>>
673                    ) {
674                        let $state: &$cipher<$($N),*> = self.0;
675                        $enc_block
676                    }
677                }
678
679                f.call(&mut EncBack(self))
680            }
681        }
682
683        impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockDecrypt for $cipher<$($N),*> {
684            fn decrypt_with_backend(&self, f: impl $crate::BlockClosure<BlockSize = $block_size>) {
685                struct DecBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>);
686
687                impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for DecBack<'a, $($N),*> {
688                    type BlockSize = $block_size;
689                }
690
691                impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for DecBack<'a, $($N),*> {
692                    type ParBlocksSize = $crate::consts::U1;
693                }
694
695                impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for DecBack<'a, $($N),*> {
696                    #[inline(always)]
697                    fn proc_block(
698                        &mut self,
699                        mut $block: $crate::inout::InOut<'_, '_, $crate::Block<Self>>
700                    ) {
701                        let $state: &$cipher<$($N),*> = self.0;
702                        $dec_block
703                    }
704                }
705
706                f.call(&mut DecBack(self))
707            }
708        }
709    };
710    (
711        $cipher:ident, $block_size:ty, $state:ident, $block:ident,
712        encrypt: $enc_block:block
713        decrypt: $dec_block:block
714    ) => {
715        $crate::impl_simple_block_encdec!(
716            <> $cipher, $block_size, $state, $block,
717            encrypt: $enc_block
718            decrypt: $dec_block
719        );
720    };
721}