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]
76 fn encrypt_blocks_b2b(
77 &self,
78 in_blocks: &[Block<Self>],
79 out_blocks: &mut [Block<Self>],
80 ) -> Result<(), NotEqualError> {
81 InOutBuf::new(in_blocks, out_blocks)
82 .map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
83 }
84}
85
86pub trait BlockCipherDecrypt: BlockSizeUser {
88 fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>);
90
91 #[inline]
93 fn decrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
94 self.decrypt_with_backend(BlockCtx { block });
95 }
96
97 #[inline]
99 fn decrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
100 self.decrypt_with_backend(BlocksCtx { blocks });
101 }
102
103 #[inline]
105 fn decrypt_block(&self, block: &mut Block<Self>) {
106 let block = block.into();
107 self.decrypt_with_backend(BlockCtx { block });
108 }
109
110 #[inline]
112 fn decrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
113 let block = (in_block, out_block).into();
114 self.decrypt_with_backend(BlockCtx { block });
115 }
116
117 #[inline]
119 fn decrypt_blocks(&self, blocks: &mut [Block<Self>]) {
120 let blocks = blocks.into();
121 self.decrypt_with_backend(BlocksCtx { blocks });
122 }
123
124 #[inline]
129 fn decrypt_blocks_b2b(
130 &self,
131 in_blocks: &[Block<Self>],
132 out_blocks: &mut [Block<Self>],
133 ) -> Result<(), NotEqualError> {
134 InOutBuf::new(in_blocks, out_blocks)
135 .map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
136 }
137}
138
139impl<Alg: BlockCipherEncrypt> BlockCipherEncrypt for &Alg {
140 fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
141 Alg::encrypt_with_backend(self, f);
142 }
143}
144
145impl<Alg: BlockCipherDecrypt> BlockCipherDecrypt for &Alg {
146 fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
147 Alg::decrypt_with_backend(self, f);
148 }
149}
150
151pub trait BlockModeEncrypt: BlockSizeUser + Sized {
157 fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure<BlockSize = Self::BlockSize>);
159
160 #[inline]
162 fn encrypt_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
163 self.encrypt_with_backend(BlockCtx { block });
164 }
165
166 #[inline]
168 fn encrypt_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
169 self.encrypt_with_backend(BlocksCtx { blocks });
170 }
171
172 #[inline]
174 fn encrypt_block(&mut self, block: &mut Block<Self>) {
175 let block = block.into();
176 self.encrypt_with_backend(BlockCtx { block });
177 }
178
179 #[inline]
181 fn encrypt_block_b2b(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
182 let block = (in_block, out_block).into();
183 self.encrypt_with_backend(BlockCtx { block });
184 }
185
186 #[inline]
188 fn encrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
189 let blocks = blocks.into();
190 self.encrypt_with_backend(BlocksCtx { blocks });
191 }
192
193 #[inline]
198 fn encrypt_blocks_b2b(
199 &mut self,
200 in_blocks: &[Block<Self>],
201 out_blocks: &mut [Block<Self>],
202 ) -> Result<(), NotEqualError> {
203 InOutBuf::new(in_blocks, out_blocks)
204 .map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
205 }
206
207 #[cfg(feature = "block-padding")]
211 #[inline]
212 fn encrypt_padded_inout<'out, P: Padding>(
213 mut self,
214 data: InOutBufReserved<'_, 'out, u8>,
215 ) -> Result<&'out [u8], PadError> {
216 let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
217 self.encrypt_blocks_inout(buf.get_blocks());
218 if let Some(block) = buf.get_tail_block() {
219 self.encrypt_block_inout(block);
220 }
221 Ok(buf.into_out())
222 }
223
224 #[cfg(feature = "block-padding")]
228 #[inline]
229 fn encrypt_padded<P: Padding>(self, buf: &mut [u8], msg_len: usize) -> Result<&[u8], PadError> {
230 let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
231 self.encrypt_padded_inout::<P>(buf)
232 }
233
234 #[cfg(feature = "block-padding")]
238 #[inline]
239 fn encrypt_padded_b2b<'a, P: Padding>(
240 self,
241 msg: &[u8],
242 out_buf: &'a mut [u8],
243 ) -> Result<&'a [u8], PadError> {
244 let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
245 self.encrypt_padded_inout::<P>(buf)
246 }
247
248 #[cfg(all(feature = "block-padding", feature = "alloc"))]
254 #[inline]
255 fn encrypt_padded_vec<P: Padding>(self, msg: &[u8]) -> Vec<u8> {
256 use block_padding::{NoPadding, ZeroPadding};
257 use common::typenum::Unsigned;
258 use core::any::TypeId;
259
260 let bs = Self::BlockSize::USIZE;
261 let msg_len = msg.len();
262
263 let pad_type_id = TypeId::of::<P>();
264 let buf_blocks_len = if pad_type_id == TypeId::of::<NoPadding>() {
265 if msg_len % bs != 0 {
266 panic!(
267 "NoPadding is used with a {msg_len}‑byte message,
268 which is not a multiple of the {bs}‑byte cipher block size"
269 );
270 }
271 msg_len / bs
272 } else if pad_type_id == TypeId::of::<ZeroPadding>() {
273 msg_len.div_ceil(bs)
274 } else {
275 1 + msg_len / bs
276 };
277
278 let mut buf = vec![0; bs * buf_blocks_len];
279 let res_len = self
280 .encrypt_padded_b2b::<P>(msg, &mut buf)
281 .expect("`buf` has enough space for encryption")
282 .len();
283 buf.truncate(res_len);
284 buf
285 }
286}
287
288pub trait BlockModeDecrypt: BlockSizeUser + Sized {
294 fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure<BlockSize = Self::BlockSize>);
296
297 #[inline]
299 fn decrypt_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
300 self.decrypt_with_backend(BlockCtx { block });
301 }
302
303 #[inline]
305 fn decrypt_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
306 self.decrypt_with_backend(BlocksCtx { blocks });
307 }
308
309 #[inline]
311 fn decrypt_block(&mut self, block: &mut Block<Self>) {
312 let block = block.into();
313 self.decrypt_with_backend(BlockCtx { block });
314 }
315
316 #[inline]
318 fn decrypt_block_b2b(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
319 let block = (in_block, out_block).into();
320 self.decrypt_with_backend(BlockCtx { block });
321 }
322
323 #[inline]
325 fn decrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
326 let blocks = blocks.into();
327 self.decrypt_with_backend(BlocksCtx { blocks });
328 }
329
330 #[inline]
335 fn decrypt_blocks_b2b(
336 &mut self,
337 in_blocks: &[Block<Self>],
338 out_blocks: &mut [Block<Self>],
339 ) -> Result<(), NotEqualError> {
340 InOutBuf::new(in_blocks, out_blocks)
341 .map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
342 }
343
344 #[cfg(feature = "block-padding")]
349 #[inline]
350 fn decrypt_padded_inout<'out, P: Padding>(
351 mut self,
352 data: InOutBuf<'_, 'out, u8>,
353 ) -> Result<&'out [u8], block_padding::Error> {
354 let (mut blocks, tail) = data.into_chunks();
355 if !tail.is_empty() {
356 return Err(block_padding::Error);
357 }
358 self.decrypt_blocks_inout(blocks.reborrow());
359 P::unpad_blocks::<Self::BlockSize>(blocks.into_out())
360 }
361
362 #[cfg(feature = "block-padding")]
367 #[inline]
368 fn decrypt_padded<P: Padding>(self, buf: &mut [u8]) -> Result<&[u8], block_padding::Error> {
369 self.decrypt_padded_inout::<P>(buf.into())
370 }
371
372 #[cfg(feature = "block-padding")]
378 #[inline]
379 fn decrypt_padded_b2b<'a, P: Padding>(
380 self,
381 in_buf: &[u8],
382 out_buf: &'a mut [u8],
383 ) -> Result<&'a [u8], block_padding::Error> {
384 if out_buf.len() < in_buf.len() {
385 return Err(block_padding::Error);
386 }
387 let n = in_buf.len();
388 let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| block_padding::Error)?;
390 self.decrypt_padded_inout::<P>(buf)
391 }
392
393 #[cfg(all(feature = "block-padding", feature = "alloc"))]
399 #[inline]
400 fn decrypt_padded_vec<P: Padding>(self, buf: &[u8]) -> Result<Vec<u8>, block_padding::Error> {
401 let mut out = vec![0; buf.len()];
402 let len = self.decrypt_padded_b2b::<P>(buf, &mut out)?.len();
403 out.truncate(len);
404 Ok(out)
405 }
406}