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
6use crate::errors::{OverflowError, StreamCipherError};
7use crate::stream_core::Counter;
8use crate::{Block, BlockDecryptMut, BlockEncryptMut};
9use inout::{InOutBuf, NotEqualError};
10
11/// Marker trait for block-level asynchronous stream ciphers
12pub 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.
78pub 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`.
148pub 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
177impl<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.
192pub 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
201macro_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
226impl_seek_num! { i32 u32 u64 u128 usize }
227