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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Cipher Feedback (CFB) mode, full-block variant (CFB-128).
//!
//! Each keystream block is `E` of the previous ciphertext block (the IV for
//! the first), and the ciphertext is fed back into the cipher. Encryption and
//! decryption differ (the feedback is always the ciphertext), so they are
//! separate methods. A (key, IV) pair must never be reused.
use super::BlockCipher;
/// CFB-128 mode wrapper around a block cipher.
#[derive(Clone)]
pub struct Cfb<C: BlockCipher> {
cipher: C,
/// Feedback block: the previous ciphertext block (IV initially), built up
/// byte-by-byte as output is produced.
feedback: [u8; 16],
/// Current keystream block, `E(feedback)` from the start of this block.
keystream: [u8; 16],
/// Bytes of the current block already processed.
pos: usize,
}
impl<C: BlockCipher> Cfb<C> {
/// Creates a CFB stream from `cipher` and a 16-byte IV.
#[inline]
pub fn new(cipher: C, iv: &[u8; 16]) -> Self {
Cfb {
cipher,
feedback: *iv,
keystream: [0u8; 16],
pos: 16, // force generation on first use
}
}
/// Recomputes the keystream from the (just-completed) feedback block.
#[inline]
fn refill(&mut self) {
self.keystream = self.feedback;
self.cipher.encrypt_block(&mut self.keystream);
self.pos = 0;
}
/// Encrypts `data` in place. May be called repeatedly across chunk
/// boundaries.
pub fn encrypt(&mut self, data: &mut [u8]) {
for byte in data.iter_mut() {
if self.pos == 16 {
self.refill();
}
let c = *byte ^ self.keystream[self.pos];
self.feedback[self.pos] = c; // ciphertext feeds the next block
*byte = c;
self.pos += 1;
}
}
/// Decrypts `data` in place. May be called repeatedly across chunk
/// boundaries.
pub fn decrypt(&mut self, data: &mut [u8]) {
for byte in data.iter_mut() {
if self.pos == 16 {
self.refill();
}
let c = *byte;
self.feedback[self.pos] = c; // ciphertext feeds the next block
*byte = c ^ self.keystream[self.pos];
self.pos += 1;
}
}
}
impl<C: BlockCipher> Drop for Cfb<C> {
fn drop(&mut self) {
// Best-effort wipe of the residual key-stream block. Same
// `core::hint::black_box`-guarded zeroing as `cipher/aes/mod.rs`.
for b in self.keystream.iter_mut() {
*b = 0;
}
let _ = core::hint::black_box(&self.keystream);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cipher::Aes128;
use crate::test_util::from_hex;
const PLAINTEXT: &str = "6bc1bee22e409f96e93d7e117393172a\
ae2d8a571e03ac9c9eb76fac45af8e51\
30c81c46a35ce411e5fbc1191a0a52ef\
f69f2445df4f9b17ad2b417be66c3710";
const KEY: &str = "2b7e151628aed2a6abf7158809cf4f3c";
const IV: &str = "000102030405060708090a0b0c0d0e0f";
// NIST SP 800-38A F.3.13 (CFB128-AES128).
const CIPHERTEXT: &str = "3b3fd92eb72dad20333449f8e83cfb4a\
c8a64537a0b3a93fcde3cdad9f1ce58b\
26751f67a3cbb140b1808cf187a4f4df\
c04b05357c5d1c0eeac4c66f9ff7f2e6";
#[test]
fn cfb_aes128_encrypt() {
let key = from_hex::<16>(KEY);
let iv = from_hex::<16>(IV);
let mut buf = from_hex::<64>(PLAINTEXT);
Cfb::new(Aes128::new(&key), &iv).encrypt(&mut buf);
assert_eq!(buf, from_hex::<64>(CIPHERTEXT));
}
#[test]
fn cfb_aes128_decrypt() {
let key = from_hex::<16>(KEY);
let iv = from_hex::<16>(IV);
let mut buf = from_hex::<64>(CIPHERTEXT);
Cfb::new(Aes128::new(&key), &iv).decrypt(&mut buf);
assert_eq!(buf, from_hex::<64>(PLAINTEXT));
}
#[test]
fn streaming_matches_oneshot() {
let key = from_hex::<16>(KEY);
let iv = from_hex::<16>(IV);
let plaintext = from_hex::<64>(PLAINTEXT);
let mut chunked = plaintext;
let mut cfb = Cfb::new(Aes128::new(&key), &iv);
let mut start = 0;
for len in [5usize, 11, 16, 1, 31] {
cfb.encrypt(&mut chunked[start..start + len]);
start += len;
}
assert_eq!(chunked, from_hex::<64>(CIPHERTEXT));
}
}