seekable_stream_cipher/
keccak.rs1use core::cmp;
2
3#[derive(Clone, Copy)]
5pub struct StreamCipher {
6 st: [u64; 25],
8}
9
10impl StreamCipher {
11 pub const KEY_LENGTH: usize = 32;
13
14 pub fn new(key: &[u8; Self::KEY_LENGTH], context: impl AsRef<[u8]>) -> Self {
21 let context = context.as_ref();
22
23 let mut st = [0u64; 25];
24 st[0] = 0x01000500cc000000;
25
26 let mut state = StreamCipher { st };
27 state.st[1] ^= u64::from_le_bytes(key[0..8].try_into().unwrap());
28 state.st[2] ^= u64::from_le_bytes(key[8..16].try_into().unwrap());
29 state.st[3] ^= u64::from_le_bytes(key[16..24].try_into().unwrap());
30 state.st[4] ^= u64::from_le_bytes(key[24..32].try_into().unwrap());
31
32 let mut context = context;
33 if context.len() > 160 {
34 let context_part_len = 160;
35 for i in 0..25 - 5 {
36 state.st[5 + i] ^= u64::from_le_bytes(context[i * 8..][0..8].try_into().unwrap());
37 }
38 context = &context[context_part_len..];
39 state.permute();
40
41 while context.len() > 160 {
42 let context_part_len = 160;
43 for i in 0..25 - 5 {
44 state.st[5 + i] ^=
45 u64::from_le_bytes(context[i * 8..][0..8].try_into().unwrap());
46 }
47 context = &context[context_part_len..];
48 state.permute();
49 }
50 }
51 let context_len = context.len();
52 let mut buf = [0u8; 160];
53 buf[..context_len].copy_from_slice(context);
54 for i in 0..25 - 5 {
55 state.st[5 + i] ^= u64::from_le_bytes(buf[i * 8..][0..8].try_into().unwrap());
56 }
57 state.st[0] ^= 0x01;
58 state.permute();
59
60 state.st[0] ^= u64::from_le_bytes(key[0..8].try_into().unwrap());
61 state.st[1] ^= u64::from_le_bytes(key[8..16].try_into().unwrap());
62 state.st[2] ^= u64::from_le_bytes(key[16..24].try_into().unwrap());
63 state.st[3] ^= u64::from_le_bytes(key[24..32].try_into().unwrap());
64
65 state
66 }
67
68 #[inline(always)]
70 fn store_rate(mut self, out: &mut [u8], block_offset: u64) {
71 let mask: [u64; 4] = self.st[0..4].try_into().unwrap();
72 self.st[4] ^= block_offset;
73 self.permute();
74 for (x, mask) in self.st[5..][0..4].iter_mut().zip(mask) {
75 *x ^= mask;
76 }
77 for i in 0..25 - 5 {
78 out[i * 8..][..8].copy_from_slice(&self.st[5 + i].to_le_bytes());
79 }
80 }
81
82 #[inline(always)]
84 fn apply_rate(mut self, out: &mut [u8], block_offset: u64) {
85 let mask: [u64; 4] = self.st[0..4].try_into().unwrap();
86 self.st[4] ^= block_offset;
87 self.permute();
88 for (x, mask) in self.st[5..][0..4].iter_mut().zip(mask) {
89 *x ^= mask;
90 }
91 for i in 0..25 - 5 {
92 let x = u64::from_le_bytes(out[i * 8..][..8].try_into().unwrap());
93 out[i * 8..][..8].copy_from_slice(&(self.st[5 + i] ^ x).to_le_bytes());
94 }
95 }
96
97 #[inline(always)]
99 fn squeeze_rate(self, block_offset: u64) -> [u8; 160] {
100 let mut out = [0u8; 160];
101 self.store_rate(&mut out, block_offset);
102 out
103 }
104
105 pub fn fill(&self, mut out: &mut [u8], start_offset: u64) -> Result<(), &'static str> {
111 if start_offset.checked_add(out.len() as u64).is_none() {
112 return Err("offset would overflow");
113 }
114 let mut block_offset = start_offset / 160;
115 let offset_in_first_block = (start_offset % 160) as usize;
116 let bytes_to_copy = cmp::min(160 - offset_in_first_block, out.len());
117 if bytes_to_copy > 0 {
118 let rate = self.squeeze_rate(block_offset);
119 out[..bytes_to_copy].copy_from_slice(&rate[offset_in_first_block..][..bytes_to_copy]);
120 out = &mut out[bytes_to_copy..];
121 }
122 while out.len() >= 160 {
123 block_offset += 1;
124 self.store_rate(&mut out[..160], block_offset);
125 out = &mut out[160..];
126 }
127 if !out.is_empty() {
128 block_offset += 1;
129 let rate = self.squeeze_rate(block_offset);
130 out.copy_from_slice(&rate[..out.len()]);
131 }
132 Ok(())
133 }
134
135 pub fn apply_keystream(
148 &self,
149 mut out: &mut [u8],
150 start_offset: u64,
151 ) -> Result<(), &'static str> {
152 if start_offset.checked_add(out.len() as u64).is_none() {
153 return Err("offset would overflow");
154 }
155 let mut block_offset = start_offset / 160;
156 let offset_in_first_block = (start_offset % 160) as usize;
157 let bytes_to_copy = cmp::min(160 - offset_in_first_block, out.len());
158 if bytes_to_copy > 0 {
159 let rate = self.squeeze_rate(block_offset);
160 for i in 0..bytes_to_copy {
161 out[i] ^= rate[offset_in_first_block + i];
162 }
163 out = &mut out[bytes_to_copy..];
164 }
165 while out.len() >= 160 {
166 block_offset += 1;
167 self.apply_rate(&mut out[..160], block_offset);
168 out = &mut out[160..];
169 }
170 if !out.is_empty() {
171 block_offset += 1;
172 let rate = self.squeeze_rate(block_offset);
173 for i in 0..out.len() {
174 out[i] ^= rate[i];
175 }
176 }
177 Ok(())
178 }
179
180 fn permute(&mut self) {
181 keccak::p1600(&mut self.st, 12);
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_keccak() {
191 let mut key = [0u8; StreamCipher::KEY_LENGTH];
192 getrandom::getrandom(&mut key).unwrap();
193
194 let st = StreamCipher::new(&key, b"test");
195
196 let mut out = [0u8; 10000];
197 st.apply_keystream(&mut out, 10).unwrap();
198
199 let mut out2 = [0u8; 10000];
200 st.fill(&mut out2, 10).unwrap();
201
202 assert_eq!(out, out2);
203
204 st.fill(&mut out2, 11).unwrap();
205 assert_eq!(out[1..], out2[0..out2.len() - 1]);
206 }
207
208 #[test]
209 fn test_large_context() {
210 let mut key = [0u8; StreamCipher::KEY_LENGTH];
211 getrandom::getrandom(&mut key).unwrap();
212 let context = [0u8; 10000];
213 let _ = StreamCipher::new(&key, context);
214 }
215}