crown/modes/cbc/
encryptor.rs

1use crate::{
2    block::{BlockCipher, BlockCipherMarker},
3    modes::BlockMode,
4    utils::subtle::xor::xor_bytes,
5};
6
7use super::CbcImpl;
8
9/// Trait for ciphers that have optimized CBC encryption implementation
10pub trait CbcEncryptor<B> {
11    /// Creates a new CBC encryptor
12    ///
13    /// # Panics
14    ///
15    /// Panics if the IV length doesn't match the block size
16    fn to_cbc_enc(self, iv: &[u8]) -> impl BlockMode + 'static;
17}
18
19pub trait CbcEncryptorMarker {}
20impl<T: BlockCipherMarker> CbcEncryptorMarker for T {}
21
22/// CBC encryptor
23struct CbcEncryptorImpl<B: BlockCipher>(CbcImpl<B>);
24
25impl CbcEncryptor<crate::block::aes::Aes> for crate::block::aes::Aes {
26    fn to_cbc_enc(self, iv: &[u8]) -> impl BlockMode + 'static {
27        crate::block::aes::cbc::CBCEncryptor::new(self, iv.try_into().unwrap())
28    }
29}
30
31impl<B: BlockCipher + CbcEncryptorMarker + 'static> CbcEncryptor<B> for B {
32    fn to_cbc_enc(self, iv: &[u8]) -> impl BlockMode + 'static {
33        if iv.len() != self.block_size() {
34            panic!(
35                "cipher.NewCBCEncrypter: IV length must equal block size: {}",
36                self.block_size()
37            );
38        }
39
40        CbcEncryptorImpl(CbcImpl::new(self, iv))
41    }
42}
43
44impl<B: BlockCipher> BlockMode for CbcEncryptorImpl<B> {
45    fn block_size(&self) -> usize {
46        self.0.block_size
47    }
48
49    fn encrypt(&mut self, inout: &mut [u8]) {
50        if inout.len() % self.0.block_size != 0 {
51            panic!("crypto/cipher: input not full blocks");
52        }
53
54        let mut iv = self.0.iv.clone();
55        let dst_chunks = inout.chunks_exact_mut(self.0.block_size);
56
57        for dst_block in dst_chunks {
58            // Write the xor to dst, then encrypt in place
59            xor_bytes(dst_block, &iv);
60            self.0.b.encrypt_block(dst_block);
61
62            // Move to the next block with this block as the next iv
63            iv.copy_from_slice(dst_block);
64        }
65
66        // Save the iv for the next CryptBlocks call
67        self.0.iv.copy_from_slice(&iv);
68    }
69    fn decrypt(&mut self, _inout: &mut [u8]) {
70        todo!()
71    }
72}