1 | //! Traits which define functionality of stream ciphers. |
2 | //! |
3 | //! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers) |
4 | //! for ciphers implementation. |
5 | |
6 | use crate::errors::{OverflowError, StreamCipherError}; |
7 | use crate::stream_core::Counter; |
8 | use crate::{Block, BlockDecryptMut, BlockEncryptMut}; |
9 | use inout::{InOutBuf, NotEqualError}; |
10 | |
11 | /// Marker trait for block-level asynchronous stream ciphers |
12 | pub trait AsyncStreamCipher: Sized { |
13 | /// Encrypt data using `InOutBuf`. |
14 | fn encrypt_inout(mut self, data: InOutBuf<'_, '_, u8>) |
15 | where |
16 | Self: BlockEncryptMut, |
17 | { |
18 | let (blocks, mut tail) = data.into_chunks(); |
19 | self.encrypt_blocks_inout_mut(blocks); |
20 | let n = tail.len(); |
21 | if n != 0 { |
22 | let mut block = Block::<Self>::default(); |
23 | block[..n].copy_from_slice(tail.get_in()); |
24 | self.encrypt_block_mut(&mut block); |
25 | tail.get_out().copy_from_slice(&block[..n]); |
26 | } |
27 | } |
28 | |
29 | /// Decrypt data using `InOutBuf`. |
30 | fn decrypt_inout(mut self, data: InOutBuf<'_, '_, u8>) |
31 | where |
32 | Self: BlockDecryptMut, |
33 | { |
34 | let (blocks, mut tail) = data.into_chunks(); |
35 | self.decrypt_blocks_inout_mut(blocks); |
36 | let n = tail.len(); |
37 | if n != 0 { |
38 | let mut block = Block::<Self>::default(); |
39 | block[..n].copy_from_slice(tail.get_in()); |
40 | self.decrypt_block_mut(&mut block); |
41 | tail.get_out().copy_from_slice(&block[..n]); |
42 | } |
43 | } |
44 | /// Encrypt data in place. |
45 | fn encrypt(self, buf: &mut [u8]) |
46 | where |
47 | Self: BlockEncryptMut, |
48 | { |
49 | self.encrypt_inout(buf.into()); |
50 | } |
51 | |
52 | /// Decrypt data in place. |
53 | fn decrypt(self, buf: &mut [u8]) |
54 | where |
55 | Self: BlockDecryptMut, |
56 | { |
57 | self.decrypt_inout(buf.into()); |
58 | } |
59 | |
60 | /// Encrypt data from buffer to buffer. |
61 | fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError> |
62 | where |
63 | Self: BlockEncryptMut, |
64 | { |
65 | InOutBuf::new(in_buf, out_buf).map(|b| self.encrypt_inout(b)) |
66 | } |
67 | |
68 | /// Decrypt data from buffer to buffer. |
69 | fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError> |
70 | where |
71 | Self: BlockDecryptMut, |
72 | { |
73 | InOutBuf::new(in_buf, out_buf).map(|b| self.decrypt_inout(b)) |
74 | } |
75 | } |
76 | |
77 | /// Synchronous stream cipher core trait. |
78 | pub trait StreamCipher { |
79 | /// Apply keystream to `inout` data. |
80 | /// |
81 | /// If end of the keystream will be achieved with the given data length, |
82 | /// method will return [`StreamCipherError`] without modifying provided `data`. |
83 | fn try_apply_keystream_inout( |
84 | &mut self, |
85 | buf: InOutBuf<'_, '_, u8>, |
86 | ) -> Result<(), StreamCipherError>; |
87 | |
88 | /// Apply keystream to data behind `buf`. |
89 | /// |
90 | /// If end of the keystream will be achieved with the given data length, |
91 | /// method will return [`StreamCipherError`] without modifying provided `data`. |
92 | #[inline ] |
93 | fn try_apply_keystream(&mut self, buf: &mut [u8]) -> Result<(), StreamCipherError> { |
94 | self.try_apply_keystream_inout(buf.into()) |
95 | } |
96 | |
97 | /// Apply keystream to `inout` data. |
98 | /// |
99 | /// It will XOR generated keystream with the data behind `in` pointer |
100 | /// and will write result to `out` pointer. |
101 | /// |
102 | /// # Panics |
103 | /// If end of the keystream will be reached with the given data length, |
104 | /// method will panic without modifying the provided `data`. |
105 | #[inline ] |
106 | fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) { |
107 | self.try_apply_keystream_inout(buf).unwrap(); |
108 | } |
109 | |
110 | /// Apply keystream to data in-place. |
111 | /// |
112 | /// It will XOR generated keystream with `data` and will write result |
113 | /// to the same buffer. |
114 | /// |
115 | /// # Panics |
116 | /// If end of the keystream will be reached with the given data length, |
117 | /// method will panic without modifying the provided `data`. |
118 | #[inline ] |
119 | fn apply_keystream(&mut self, buf: &mut [u8]) { |
120 | self.try_apply_keystream(buf).unwrap(); |
121 | } |
122 | |
123 | /// Apply keystream to data buffer-to-buffer. |
124 | /// |
125 | /// It will XOR generated keystream with data from the `input` buffer |
126 | /// and will write result to the `output` buffer. |
127 | /// |
128 | /// Returns [`StreamCipherError`] if provided `in_blocks` and `out_blocks` |
129 | /// have different lengths or if end of the keystream will be reached with |
130 | /// the given input data length. |
131 | #[inline ] |
132 | fn apply_keystream_b2b( |
133 | &mut self, |
134 | input: &[u8], |
135 | output: &mut [u8], |
136 | ) -> Result<(), StreamCipherError> { |
137 | InOutBuf::new(input, output) |
138 | .map_err(|_| StreamCipherError) |
139 | .and_then(|buf| self.try_apply_keystream_inout(buf)) |
140 | } |
141 | } |
142 | |
143 | /// Trait for seekable stream ciphers. |
144 | /// |
145 | /// Methods of this trait are generic over the [`SeekNum`] trait, which is |
146 | /// implemented for primitive numeric types, i.e.: `i32`, `u32`, `u64`, |
147 | /// `u128`, and `usize`. |
148 | pub trait StreamCipherSeek { |
149 | /// Try to get current keystream position |
150 | /// |
151 | /// Returns [`OverflowError`] if position can not be represented by type `T` |
152 | fn try_current_pos<T: SeekNum>(&self) -> Result<T, OverflowError>; |
153 | |
154 | /// Try to seek to the given position |
155 | /// |
156 | /// Returns [`StreamCipherError`] if provided position value is bigger than |
157 | /// keystream length. |
158 | fn try_seek<T: SeekNum>(&mut self, pos: T) -> Result<(), StreamCipherError>; |
159 | |
160 | /// Get current keystream position |
161 | /// |
162 | /// # Panics |
163 | /// If position can not be represented by type `T` |
164 | fn current_pos<T: SeekNum>(&self) -> T { |
165 | self.try_current_pos().unwrap() |
166 | } |
167 | |
168 | /// Seek to the given position |
169 | /// |
170 | /// # Panics |
171 | /// If provided position value is bigger than keystream length |
172 | fn seek<T: SeekNum>(&mut self, pos: T) { |
173 | self.try_seek(pos).unwrap() |
174 | } |
175 | } |
176 | |
177 | impl<C: StreamCipher> StreamCipher for &mut C { |
178 | #[inline ] |
179 | fn try_apply_keystream_inout( |
180 | &mut self, |
181 | buf: InOutBuf<'_, '_, u8>, |
182 | ) -> Result<(), StreamCipherError> { |
183 | C::try_apply_keystream_inout(self, buf) |
184 | } |
185 | } |
186 | |
187 | /// Trait implemented for numeric types which can be used with the |
188 | /// [`StreamCipherSeek`] trait. |
189 | /// |
190 | /// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`. |
191 | /// It is not intended to be implemented in third-party crates. |
192 | pub trait SeekNum: Sized { |
193 | /// Try to get position for block number `block`, byte position inside |
194 | /// block `byte`, and block size `bs`. |
195 | fn from_block_byte<T: Counter>(block: T, byte: u8, bs: u8) -> Result<Self, OverflowError>; |
196 | |
197 | /// Try to get block number and bytes position for given block size `bs`. |
198 | fn into_block_byte<T: Counter>(self, bs: u8) -> Result<(T, u8), OverflowError>; |
199 | } |
200 | |
201 | macro_rules! impl_seek_num { |
202 | {$($t:ty )*} => { |
203 | $( |
204 | impl SeekNum for $t { |
205 | fn from_block_byte<T: Counter>(block: T, byte: u8, bs: u8) -> Result<Self, OverflowError> { |
206 | debug_assert!(byte < bs); |
207 | let mut block: Self = block.try_into().map_err(|_| OverflowError)?; |
208 | if byte != 0 { |
209 | block -= 1; |
210 | } |
211 | let pos = block.checked_mul(bs as Self).ok_or(OverflowError)? + (byte as Self); |
212 | Ok(pos) |
213 | } |
214 | |
215 | fn into_block_byte<T: Counter>(self, bs: u8) -> Result<(T, u8), OverflowError> { |
216 | let bs = bs as Self; |
217 | let byte = self % bs; |
218 | let block = T::try_from(self/bs).map_err(|_| OverflowError)?; |
219 | Ok((block, byte as u8)) |
220 | } |
221 | } |
222 | )* |
223 | }; |
224 | } |
225 | |
226 | impl_seek_num! { i32 u32 u64 u128 usize } |
227 | |