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: InOutBuf<'_, '_, GenericArray<…, …>>, tail: InOutBuf<'_, '_, GenericArray<…, …>>) = self.blocks.into_chunks();
625 for chunk: InOut<'_, '_, GenericArray<…, …>> in chunks {
626 backend.proc_par_blocks(chunk);
627 }
628 backend.proc_tail_blocks(tail);
629 } else {
630 for block: InOut<'_, '_, GenericArray<…, …>> 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}
722