| 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<'inp, 'out, GenericArray<…, …>> in chunks { |
| 626 | backend.proc_par_blocks(chunk); |
| 627 | } |
| 628 | backend.proc_tail_blocks(tail); |
| 629 | } else { |
| 630 | for block: InOut<'inp, 'out, 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 |
Definitions
- BlockCipher
- BlockBackend
- proc_block
- proc_par_blocks
- proc_tail_blocks
- proc_block_inplace
- proc_par_blocks_inplace
- proc_tail_blocks_inplace
- BlockClosure
- call
- BlockEncrypt
- encrypt_with_backend
- encrypt_block_inout
- encrypt_blocks_inout
- encrypt_block
- encrypt_block_b2b
- encrypt_blocks
- encrypt_blocks_b2b
- BlockDecrypt
- decrypt_with_backend
- decrypt_block_inout
- decrypt_blocks_inout
- decrypt_block
- decrypt_block_b2b
- decrypt_blocks
- decrypt_blocks_b2b
- BlockEncryptMut
- encrypt_with_backend_mut
- encrypt_block_inout_mut
- encrypt_blocks_inout_mut
- encrypt_block_mut
- encrypt_block_b2b_mut
- encrypt_blocks_mut
- encrypt_blocks_b2b_mut
- BlockDecryptMut
- decrypt_with_backend_mut
- decrypt_block_inout_mut
- decrypt_blocks_inout_mut
- decrypt_block_mut
- decrypt_block_b2b_mut
- decrypt_blocks_mut
- decrypt_blocks_b2b_mut
- encrypt_with_backend_mut
- decrypt_with_backend_mut
- encrypt_with_backend
- decrypt_with_backend
- BlockCtx
- block
- BlockSize
- call
- BlocksCtx
- blocks
- BlockSize
- call
Learn Rust with the experts
Find out more
