cipher/
stream.rs

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 }