1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use crate::types::CryptResult;
use crate::{
    paddings::{Padding, ZeroPadding},
    rijndael::Rijndael,
};

#[derive(Debug)]
pub struct RijndaelCbc<P: Padding> {
    pub rijndael: Rijndael,
    pub padding: P,
}

impl RijndaelCbc<ZeroPadding> {
    #[inline(always)]
    pub fn new(key: Vec<u8>, block_size: usize) -> Result<Self, &'static str> {
        Ok(Self {
            rijndael: Rijndael::new(key, block_size)?,
            padding: ZeroPadding(block_size),
        })
    }

    #[inline(always)]
    pub fn encrypt(&self, iv: Vec<u8>, source: Vec<u8>) -> Result<CryptResult, &'static str> {
        let ppt = self.padding.encode(source);
        let mut offset = 0;
        let mut ct = Vec::with_capacity(ppt.len());
        let mut v = iv;
        loop {
            let mut block = ppt[offset..(offset + self.rijndael.block_size)].into();
            block = self.x_or_block(&block, &v);
            block = self.rijndael.encrypt(&block)?;
            ct.extend(block.clone());
            offset += self.rijndael.block_size;

            if offset >= ppt.len() {
                break;
            }
            v = block;
        }
        Ok(ct)
    }

    #[inline(always)]
    pub fn decrypt(&self, iv: Vec<u8>, cipher: Vec<u8>) -> Result<CryptResult, &'static str> {
        if (cipher.len() % self.rijndael.block_size) != 0 {
            return Err("Invalid size");
        }
        let mut ppt = Vec::with_capacity(cipher.len());
        let mut offset = 0;
        let mut v = iv;
        loop {
            let block = cipher[offset..(offset + self.rijndael.block_size)].into();
            let decrypted = self.rijndael.decrypt(&block)?;
            ppt.extend(self.x_or_block(&decrypted, &v));
            offset += self.rijndael.block_size;

            if offset >= cipher.len() {
                break;
            }
            v = block;
        }
        Ok(self.padding.decode(ppt)?)
    }

    #[inline(always)]
    pub fn x_or_block(&self, b1: &Vec<u8>, b2: &Vec<u8>) -> Vec<u8> {
        (0..self.rijndael.block_size)
            .map(|i| b1[i] ^ b2[i])
            .collect()
    }
}