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 self.st[4] ^= block_offset;
72 let mask = self.st;
73 self.permute();
74 for (x, mask) in self.st.iter_mut().zip(mask) {
75 *x ^= mask;
76 }
77 for i in 0..25 {
78 out[i * 8..][..8].copy_from_slice(&self.st[i].to_le_bytes());
79 }
80 }
81
82 #[inline(always)]
84 fn apply_rate(mut self, out: &mut [u8], block_offset: u64) {
85 self.st[4] ^= block_offset;
86 let mask = self.st;
87 self.permute();
88 for (x, mask) in self.st.iter_mut().zip(mask) {
89 *x ^= mask;
90 }
91 for i in 0..25 {
92 let x = u64::from_le_bytes(out[i * 8..][..8].try_into().unwrap());
93 out[i * 8..][..8].copy_from_slice(&(self.st[i] ^ x).to_le_bytes());
94 }
95 }
96
97 #[inline(always)]
99 fn squeeze_rate(self, block_offset: u64) -> [u8; 200] {
100 let mut out = [0u8; 200];
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 / 200;
115 let offset_in_first_block = (start_offset % 200) as usize;
116 if offset_in_first_block != 0 {
117 let bytes_to_copy = cmp::min(200 - offset_in_first_block, out.len());
118 if bytes_to_copy > 0 {
119 let rate = self.squeeze_rate(block_offset);
120 out[..bytes_to_copy]
121 .copy_from_slice(&rate[offset_in_first_block..][..bytes_to_copy]);
122 out = &mut out[bytes_to_copy..];
123 }
124 block_offset += 1;
125 }
126 while out.len() >= 200 {
127 self.store_rate(&mut out[..200], block_offset);
128 block_offset += 1;
129 out = &mut out[200..];
130 }
131 if !out.is_empty() {
132 let rate = self.squeeze_rate(block_offset);
133 out.copy_from_slice(&rate[..out.len()]);
134 }
135 Ok(())
136 }
137
138 pub fn apply_keystream(
151 &self,
152 mut out: &mut [u8],
153 start_offset: u64,
154 ) -> Result<(), &'static str> {
155 if start_offset.checked_add(out.len() as u64).is_none() {
156 return Err("offset would overflow");
157 }
158 let mut block_offset = start_offset / 200;
159 let offset_in_first_block = (start_offset % 200) as usize;
160 if offset_in_first_block != 0 {
161 let bytes_to_copy = cmp::min(200 - offset_in_first_block, out.len());
162 if bytes_to_copy > 0 {
163 let rate = self.squeeze_rate(block_offset);
164 for i in 0..bytes_to_copy {
165 out[i] ^= rate[offset_in_first_block + i];
166 }
167 out = &mut out[bytes_to_copy..];
168 }
169 block_offset += 1;
170 }
171 while out.len() >= 200 {
172 self.apply_rate(&mut out[..200], block_offset);
173 block_offset += 1;
174 out = &mut out[200..];
175 }
176 if !out.is_empty() {
177 let rate = self.squeeze_rate(block_offset);
178 for i in 0..out.len() {
179 out[i] ^= rate[i];
180 }
181 }
182 Ok(())
183 }
184
185 fn permute(&mut self) {
186 keccak::Keccak::new().with_p1600::<12>(|f| f(&mut self.st));
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_keccak() {
196 let mut key = [0u8; StreamCipher::KEY_LENGTH];
197 getrandom::fill(&mut key).unwrap();
198
199 let st = StreamCipher::new(&key, b"test");
200
201 let mut out = [0u8; 10000];
202 st.apply_keystream(&mut out, 10).unwrap();
203
204 let mut out2 = [0u8; 10000];
205 st.fill(&mut out2, 10).unwrap();
206
207 assert_eq!(out, out2);
208
209 st.fill(&mut out2, 11).unwrap();
210 assert_eq!(out[1..], out2[0..out2.len() - 1]);
211
212 out.fill(0);
213 st.apply_keystream(&mut out, 0).unwrap();
214 st.fill(&mut out2, 0).unwrap();
215 assert_eq!(out, out2);
216
217 st.fill(&mut out, 200).unwrap();
218 assert_eq!(out[..out2.len() - 200], out2[200..]);
219 }
220
221 #[test]
222 fn test_large_context() {
223 let mut key = [0u8; StreamCipher::KEY_LENGTH];
224 getrandom::fill(&mut key).unwrap();
225 let context = [0u8; 10000];
226 let _ = StreamCipher::new(&key, context);
227 }
228}