dcrypt_algorithms/block/modes/cbc/
mod.rs1#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14use super::super::{BlockCipher, CipherAlgorithm};
15use crate::error::{validate, Error, Result};
16use crate::types::Nonce;
17
18pub trait CbcCompatible: crate::types::sealed::Sealed {}
20
21impl<const N: usize> CbcCompatible for Nonce<N> {}
23
24#[derive(Clone, Zeroize, ZeroizeOnDrop)]
26pub struct Cbc<B: BlockCipher + Zeroize + ZeroizeOnDrop> {
27 cipher: B,
28 iv: Vec<u8>,
29}
30
31impl<B: BlockCipher + CipherAlgorithm + Zeroize + ZeroizeOnDrop> Cbc<B> {
32 pub fn new<const N: usize>(cipher: B, iv: &Nonce<N>) -> Result<Self>
36 where
37 Nonce<N>: CbcCompatible,
38 {
39 validate::length("CBC initialization vector", N, B::block_size())?;
41
42 Ok(Self {
43 cipher,
44 iv: iv.as_ref().to_vec(),
45 })
46 }
47
48 pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
54 let block_size = B::block_size();
56 if plaintext.len() % block_size != 0 {
57 let expected_len = ((plaintext.len() / block_size) + 1) * block_size;
58 return Err(Error::Length {
59 context: "CBC plaintext",
60 expected: expected_len,
61 actual: plaintext.len(),
62 });
63 }
64
65 let mut ciphertext = Vec::with_capacity(plaintext.len());
66 let mut prev_block = self.iv.clone();
67
68 for chunk in plaintext.chunks(block_size) {
70 let mut block = [0u8; 16]; block[..chunk.len()].copy_from_slice(chunk);
72
73 for i in 0..block_size {
75 block[i] ^= prev_block[i];
76 }
77
78 self.cipher.encrypt_block(&mut block)?;
80
81 ciphertext.extend_from_slice(&block);
83 prev_block = block.to_vec();
84 }
85
86 Ok(ciphertext)
87 }
88
89 pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
93 let block_size = B::block_size();
95 if ciphertext.len() % block_size != 0 {
96 let expected_len = ((ciphertext.len() / block_size) + 1) * block_size;
97 return Err(Error::Length {
98 context: "CBC ciphertext",
99 expected: expected_len,
100 actual: ciphertext.len(),
101 });
102 }
103
104 let mut plaintext = Vec::with_capacity(ciphertext.len());
105 let mut prev_block = self.iv.clone();
106
107 for chunk in ciphertext.chunks(block_size) {
109 let mut block = [0u8; 16]; block[..chunk.len()].copy_from_slice(chunk);
111
112 let current_block = block;
114
115 self.cipher.decrypt_block(&mut block)?;
117
118 for i in 0..block_size {
120 block[i] ^= prev_block[i];
121 }
122
123 plaintext.extend_from_slice(&block);
125 prev_block = current_block.to_vec();
126 }
127
128 Ok(plaintext)
129 }
130}
131
132#[cfg(test)]
133mod tests;