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 | |
13 | use crate::{ParBlocks, ParBlocksSizeUser}; |
14 | #[cfg (all(feature = "block-padding" , feature = "alloc" ))] |
15 | use alloc::{vec, vec::Vec}; |
16 | #[cfg (feature = "block-padding" )] |
17 | use inout::{ |
18 | block_padding::{Padding, UnpadError}, |
19 | InOutBufReserved, PadError, |
20 | }; |
21 | use inout::{InOut, InOutBuf, NotEqualError}; |
22 | |
23 | pub use crypto_common::{generic_array::ArrayLength, typenum::Unsigned, Block, BlockSizeUser}; |
24 | |
25 | /// Marker trait for block ciphers. |
26 | pub trait BlockCipher: BlockSizeUser {} |
27 | |
28 | /// Trait implemented by block cipher encryption and decryption backends. |
29 | pub 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. |
74 | pub 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. |
80 | pub 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. |
195 | pub 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. |
325 | pub 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. |
444 | pub 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 | |
569 | impl<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 | |
575 | impl<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 | |
581 | impl<Alg: BlockCipher> BlockCipher for &Alg {} |
582 | |
583 | impl<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 | |
589 | impl<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. |
596 | struct BlockCtx<'inp, 'out, BS: ArrayLength<u8>> { |
597 | block: InOut<'inp, 'out, Block<Self>>, |
598 | } |
599 | |
600 | impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for BlockCtx<'inp, 'out, BS> { |
601 | type BlockSize = BS; |
602 | } |
603 | |
604 | impl<'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. |
612 | struct BlocksCtx<'inp, 'out, BS: ArrayLength<u8>> { |
613 | blocks: InOutBuf<'inp, 'out, Block<Self>>, |
614 | } |
615 | |
616 | impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for BlocksCtx<'inp, 'out, BS> { |
617 | type BlockSize = BS; |
618 | } |
619 | |
620 | impl<'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" ))] |
638 | fn 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 ] |
645 | macro_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 | |