1#[cfg(all(feature = "block-padding", feature = "alloc"))]
14use alloc::{vec, vec::Vec};
15use common::{Block, BlockSizeUser};
16use inout::{InOut, InOutBuf, NotEqualError};
17#[cfg(feature = "block-padding")]
18use inout::{
19 InOutBufReserved, PadError,
20 block_padding::{self, Padding},
21};
22
23mod backends;
24mod ctx;
25
26use ctx::{BlockCtx, BlocksCtx};
27
28pub use backends::{
29 BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherEncBackend, BlockCipherEncClosure,
30 BlockModeDecBackend, BlockModeDecClosure, BlockModeEncBackend, BlockModeEncClosure,
31};
32
33pub trait BlockCipherEncrypt: BlockSizeUser + Sized {
35 fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>);
37
38 #[inline]
40 fn encrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
41 self.encrypt_with_backend(BlockCtx { block });
42 }
43
44 #[inline]
46 fn encrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
47 self.encrypt_with_backend(BlocksCtx { blocks });
48 }
49
50 #[inline]
52 fn encrypt_block(&self, block: &mut Block<Self>) {
53 let block = block.into();
54 self.encrypt_with_backend(BlockCtx { block });
55 }
56
57 #[inline]
59 fn encrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
60 let block = (in_block, out_block).into();
61 self.encrypt_with_backend(BlockCtx { block });
62 }
63
64 #[inline]
66 fn encrypt_blocks(&self, blocks: &mut [Block<Self>]) {
67 let blocks = blocks.into();
68 self.encrypt_with_backend(BlocksCtx { blocks });
69 }
70
71 #[inline]
77 fn encrypt_blocks_b2b(
78 &self,
79 in_blocks: &[Block<Self>],
80 out_blocks: &mut [Block<Self>],
81 ) -> Result<(), NotEqualError> {
82 InOutBuf::new(in_blocks, out_blocks)
83 .map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
84 }
85}
86
87pub trait BlockCipherDecrypt: BlockSizeUser {
89 fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>);
91
92 #[inline]
94 fn decrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
95 self.decrypt_with_backend(BlockCtx { block });
96 }
97
98 #[inline]
100 fn decrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
101 self.decrypt_with_backend(BlocksCtx { blocks });
102 }
103
104 #[inline]
106 fn decrypt_block(&self, block: &mut Block<Self>) {
107 let block = block.into();
108 self.decrypt_with_backend(BlockCtx { block });
109 }
110
111 #[inline]
113 fn decrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
114 let block = (in_block, out_block).into();
115 self.decrypt_with_backend(BlockCtx { block });
116 }
117
118 #[inline]
120 fn decrypt_blocks(&self, blocks: &mut [Block<Self>]) {
121 let blocks = blocks.into();
122 self.decrypt_with_backend(BlocksCtx { blocks });
123 }
124
125 #[inline]
131 fn decrypt_blocks_b2b(
132 &self,
133 in_blocks: &[Block<Self>],
134 out_blocks: &mut [Block<Self>],
135 ) -> Result<(), NotEqualError> {
136 InOutBuf::new(in_blocks, out_blocks)
137 .map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
138 }
139}
140
141impl<Alg: BlockCipherEncrypt> BlockCipherEncrypt for &Alg {
142 fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
143 Alg::encrypt_with_backend(self, f);
144 }
145}
146
147impl<Alg: BlockCipherDecrypt> BlockCipherDecrypt for &Alg {
148 fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
149 Alg::decrypt_with_backend(self, f);
150 }
151}
152
153pub trait BlockModeEncrypt: BlockSizeUser + Sized {
159 fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure<BlockSize = Self::BlockSize>);
161
162 #[inline]
164 fn encrypt_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
165 self.encrypt_with_backend(BlockCtx { block });
166 }
167
168 #[inline]
170 fn encrypt_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
171 self.encrypt_with_backend(BlocksCtx { blocks });
172 }
173
174 #[inline]
176 fn encrypt_block(&mut self, block: &mut Block<Self>) {
177 let block = block.into();
178 self.encrypt_with_backend(BlockCtx { block });
179 }
180
181 #[inline]
183 fn encrypt_block_b2b(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
184 let block = (in_block, out_block).into();
185 self.encrypt_with_backend(BlockCtx { block });
186 }
187
188 #[inline]
190 fn encrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
191 let blocks = blocks.into();
192 self.encrypt_with_backend(BlocksCtx { blocks });
193 }
194
195 #[inline]
201 fn encrypt_blocks_b2b(
202 &mut self,
203 in_blocks: &[Block<Self>],
204 out_blocks: &mut [Block<Self>],
205 ) -> Result<(), NotEqualError> {
206 InOutBuf::new(in_blocks, out_blocks)
207 .map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
208 }
209
210 #[cfg(feature = "block-padding")]
215 #[inline]
216 fn encrypt_padded_inout<'out, P: Padding>(
217 mut self,
218 data: InOutBufReserved<'_, 'out, u8>,
219 ) -> Result<&'out [u8], PadError> {
220 let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
221 self.encrypt_blocks_inout(buf.get_blocks());
222 if let Some(block) = buf.get_tail_block() {
223 self.encrypt_block_inout(block);
224 }
225 Ok(buf.into_out())
226 }
227
228 #[cfg(feature = "block-padding")]
233 #[inline]
234 fn encrypt_padded<P: Padding>(self, buf: &mut [u8], msg_len: usize) -> Result<&[u8], PadError> {
235 let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
236 self.encrypt_padded_inout::<P>(buf)
237 }
238
239 #[cfg(feature = "block-padding")]
244 #[inline]
245 fn encrypt_padded_b2b<'a, P: Padding>(
246 self,
247 msg: &[u8],
248 out_buf: &'a mut [u8],
249 ) -> Result<&'a [u8], PadError> {
250 let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
251 self.encrypt_padded_inout::<P>(buf)
252 }
253
254 #[cfg(all(feature = "block-padding", feature = "alloc"))]
260 #[inline]
261 fn encrypt_padded_vec<P: Padding>(self, msg: &[u8]) -> Vec<u8> {
262 use block_padding::{NoPadding, ZeroPadding};
263 use common::typenum::Unsigned;
264 use core::any::TypeId;
265
266 let bs = Self::BlockSize::USIZE;
267 let msg_len = msg.len();
268
269 let pad_type_id = TypeId::of::<P>();
270 let buf_blocks_len = if pad_type_id == TypeId::of::<NoPadding>() {
271 assert!(
272 msg_len % bs == 0,
273 "NoPadding is used with a {msg_len}‑byte message,
274 which is not a multiple of the {bs}‑byte cipher block size"
275 );
276 msg_len / bs
277 } else if pad_type_id == TypeId::of::<ZeroPadding>() {
278 msg_len.div_ceil(bs)
279 } else {
280 1 + msg_len / bs
281 };
282
283 let mut buf = vec![0; bs * buf_blocks_len];
284 let res_len = self
285 .encrypt_padded_b2b::<P>(msg, &mut buf)
286 .expect("`buf` has enough space for encryption")
287 .len();
288 buf.truncate(res_len);
289 buf
290 }
291}
292
293pub trait BlockModeDecrypt: BlockSizeUser + Sized {
299 fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure<BlockSize = Self::BlockSize>);
301
302 #[inline]
304 fn decrypt_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
305 self.decrypt_with_backend(BlockCtx { block });
306 }
307
308 #[inline]
310 fn decrypt_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
311 self.decrypt_with_backend(BlocksCtx { blocks });
312 }
313
314 #[inline]
316 fn decrypt_block(&mut self, block: &mut Block<Self>) {
317 let block = block.into();
318 self.decrypt_with_backend(BlockCtx { block });
319 }
320
321 #[inline]
323 fn decrypt_block_b2b(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
324 let block = (in_block, out_block).into();
325 self.decrypt_with_backend(BlockCtx { block });
326 }
327
328 #[inline]
330 fn decrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
331 let blocks = blocks.into();
332 self.decrypt_with_backend(BlocksCtx { blocks });
333 }
334
335 #[inline]
341 fn decrypt_blocks_b2b(
342 &mut self,
343 in_blocks: &[Block<Self>],
344 out_blocks: &mut [Block<Self>],
345 ) -> Result<(), NotEqualError> {
346 InOutBuf::new(in_blocks, out_blocks)
347 .map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
348 }
349
350 #[cfg(feature = "block-padding")]
356 #[inline]
357 fn decrypt_padded_inout<'out, P: Padding>(
358 mut self,
359 data: InOutBuf<'_, 'out, u8>,
360 ) -> Result<&'out [u8], block_padding::Error> {
361 let (mut blocks, tail) = data.into_chunks();
362 if !tail.is_empty() {
363 return Err(block_padding::Error);
364 }
365 self.decrypt_blocks_inout(blocks.reborrow());
366 P::unpad_blocks::<Self::BlockSize>(blocks.into_out())
367 }
368
369 #[cfg(feature = "block-padding")]
375 #[inline]
376 fn decrypt_padded<P: Padding>(self, buf: &mut [u8]) -> Result<&[u8], block_padding::Error> {
377 self.decrypt_padded_inout::<P>(buf.into())
378 }
379
380 #[cfg(feature = "block-padding")]
387 #[inline]
388 fn decrypt_padded_b2b<'a, P: Padding>(
389 self,
390 in_buf: &[u8],
391 out_buf: &'a mut [u8],
392 ) -> Result<&'a [u8], block_padding::Error> {
393 if out_buf.len() < in_buf.len() {
394 return Err(block_padding::Error);
395 }
396 let n = in_buf.len();
397 let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| block_padding::Error)?;
399 self.decrypt_padded_inout::<P>(buf)
400 }
401
402 #[cfg(all(feature = "block-padding", feature = "alloc"))]
409 #[inline]
410 fn decrypt_padded_vec<P: Padding>(self, buf: &[u8]) -> Result<Vec<u8>, block_padding::Error> {
411 let mut out = vec![0; buf.len()];
412 let len = self.decrypt_padded_b2b::<P>(buf, &mut out)?.len();
413 out.truncate(len);
414 Ok(out)
415 }
416}