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
//! Output Feedback (OFB) mode — a stream cipher built from a [`BlockCipher`].
//!
//! The keystream is `E(IV) ‖ E(E(IV)) ‖ …`: each block is the encryption of
//! the previous keystream block. Like CTR it is a synchronous stream cipher,
//! so encryption and decryption are the same XOR operation, and a (key, IV)
//! pair must never be reused.
use super::BlockCipher;
/// OFB-mode stream wrapper around a block cipher.
#[derive(Clone)]
pub struct Ofb<C: BlockCipher> {
cipher: C,
/// Current keystream block, fed back into the cipher to produce the next.
block: [u8; 16],
/// Bytes of `block` already consumed (`16` ⇒ a fresh block is needed).
pos: usize,
}
impl<C: BlockCipher> Ofb<C> {
/// Creates an OFB stream from `cipher` and a 16-byte IV.
#[inline]
pub fn new(cipher: C, iv: &[u8; 16]) -> Self {
Ofb {
cipher,
block: *iv,
pos: 16, // force generation on first use
}
}
#[inline]
fn refill(&mut self) {
self.cipher.encrypt_block(&mut self.block);
self.pos = 0;
}
/// XORs the keystream into `data` in place, encrypting or decrypting it.
///
/// May be called repeatedly; the keystream continues seamlessly across
/// calls regardless of chunk boundaries.
pub fn apply_keystream(&mut self, data: &mut [u8]) {
for byte in data.iter_mut() {
if self.pos == 16 {
self.refill();
}
*byte ^= self.block[self.pos];
self.pos += 1;
}
}
}
impl<C: BlockCipher> Drop for Ofb<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.block.iter_mut() {
*b = 0;
}
let _ = core::hint::black_box(&self.block);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cipher::Aes128;
use crate::test_util::from_hex;
const PLAINTEXT: &str = "6bc1bee22e409f96e93d7e117393172a\
ae2d8a571e03ac9c9eb76fac45af8e51\
30c81c46a35ce411e5fbc1191a0a52ef\
f69f2445df4f9b17ad2b417be66c3710";
#[test]
fn ofb_aes128() {
// NIST SP 800-38A F.4.1.
let key = from_hex::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let iv = from_hex::<16>("000102030405060708090a0b0c0d0e0f");
let mut buf = from_hex::<64>(PLAINTEXT);
let expected = from_hex::<64>(
"3b3fd92eb72dad20333449f8e83cfb4a\
7789508d16918f03f53c52dac54ed825\
9740051e9c5fecf64344f7a82260edcc\
304c6528f659c77866a510d9c1d6ae5e",
);
Ofb::new(Aes128::new(&key), &iv).apply_keystream(&mut buf);
assert_eq!(buf, expected);
// OFB is its own inverse.
Ofb::new(Aes128::new(&key), &iv).apply_keystream(&mut buf);
assert_eq!(buf, from_hex::<64>(PLAINTEXT));
}
}