1use aes::Aes128;
15use aes::cipher::{BlockCipherEncrypt, KeyInit, KeyIvInit};
16
17const BATCH: usize = 64;
19
20pub struct Cfb8Encryptor {
22 inner: cfb8::Encryptor<Aes128>,
23}
24
25impl std::fmt::Debug for Cfb8Encryptor {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.write_str("Cfb8Encryptor { .. }")
28 }
29}
30
31impl Cfb8Encryptor {
32 pub fn new(secret: &[u8; 16]) -> Self {
34 Cfb8Encryptor {
35 inner: cfb8::Encryptor::<Aes128>::new(&(*secret).into(), &(*secret).into()),
36 }
37 }
38
39 #[inline]
41 pub fn encrypt(&mut self, buf: &mut [u8]) {
42 self.inner.encrypt(buf);
43 }
44}
45
46pub struct Cfb8Decryptor {
48 cipher: Aes128,
49 shift: [u8; 16],
51 blocks: Box<[aes::Block; BATCH]>,
53}
54
55impl std::fmt::Debug for Cfb8Decryptor {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str("Cfb8Decryptor { .. }")
58 }
59}
60
61impl Cfb8Decryptor {
62 pub fn new(secret: &[u8; 16]) -> Self {
64 Cfb8Decryptor {
65 cipher: Aes128::new(&(*secret).into()),
66 shift: *secret,
67 blocks: Box::new([aes::Block::default(); BATCH]),
68 }
69 }
70
71 pub fn decrypt(&mut self, buf: &mut [u8]) {
73 let mut window = [0u8; 16 + BATCH];
76 for chunk in buf.chunks_mut(BATCH) {
77 let n = chunk.len();
78 window[..16].copy_from_slice(&self.shift);
79 window[16..16 + n].copy_from_slice(chunk);
80 for (i, block) in self.blocks[..n].iter_mut().enumerate() {
81 block.copy_from_slice(&window[i..i + 16]);
82 }
83 self.cipher.encrypt_blocks(&mut self.blocks[..n]);
84 for (b, ks) in chunk.iter_mut().zip(self.blocks[..n].iter()) {
85 *b ^= ks[0];
86 }
87 self.shift.copy_from_slice(&window[n..n + 16]);
88 }
89 }
90}
91
92#[derive(Debug)]
94pub struct CipherPair {
95 pub encryptor: Cfb8Encryptor,
97 pub decryptor: Cfb8Decryptor,
99}
100
101impl CipherPair {
102 pub fn new(secret: &[u8; 16]) -> Self {
104 CipherPair {
105 encryptor: Cfb8Encryptor::new(secret),
106 decryptor: Cfb8Decryptor::new(secret),
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 fn hex(s: &str) -> Vec<u8> {
116 (0..s.len())
117 .step_by(2)
118 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
119 .collect()
120 }
121
122 #[test]
125 fn nist_sp800_38a_cfb8() {
126 let key: [u8; 16] = hex("2b7e151628aed2a6abf7158809cf4f3c").try_into().unwrap();
127 let iv: [u8; 16] = hex("000102030405060708090a0b0c0d0e0f").try_into().unwrap();
128 let pt = hex("6bc1bee22e409f96e93d7e117393172aae2d");
129 let ct = hex("3b79424c9c0dd436bace9e0ed4586a4f32b9");
130
131 let mut enc = cfb8::Encryptor::<Aes128>::new(&key.into(), &iv.into());
132 let mut buf = pt.clone();
133 enc.encrypt(&mut buf);
134 assert_eq!(buf, ct);
135
136 let mut dec = Cfb8Decryptor {
137 cipher: Aes128::new(&key.into()),
138 shift: iv,
139 blocks: Box::new([aes::Block::default(); BATCH]),
140 };
141 let mut buf = ct.clone();
142 dec.decrypt(&mut buf);
143 assert_eq!(buf, pt);
144 }
145
146 #[test]
147 fn stream_in_pieces_matches_reference() {
148 let secret = [7u8; 16];
149 let data: Vec<u8> = (0..5000u32)
150 .map(|i| (i.wrapping_mul(2654435761) >> 13) as u8)
151 .collect();
152 let mut ct = data.clone();
153 let mut enc = Cfb8Encryptor::new(&secret);
154 let mut off = 0;
156 for step in [1, 15, 16, 17, 63, 64, 65, 200, 1000].iter().cycle() {
157 if off >= ct.len() {
158 break;
159 }
160 let end = (off + step).min(ct.len());
161 enc.encrypt(&mut ct[off..end]);
162 off = end;
163 }
164 let mut reference = ct.clone();
166 cfb8::Decryptor::<Aes128>::new(&secret.into(), &secret.into()).decrypt(&mut reference);
167 assert_eq!(reference, data);
168 let mut pt = ct.clone();
170 let mut dec = Cfb8Decryptor::new(&secret);
171 let mut off = 0;
172 for step in [3, 64, 1, 129, 7, 4096].iter().cycle() {
173 if off >= pt.len() {
174 break;
175 }
176 let end = (off + step).min(pt.len());
177 dec.decrypt(&mut pt[off..end]);
178 off = end;
179 }
180 assert_eq!(pt, data);
181 }
182}