11//! Traits which define functionality of stream ciphers.
22//!
3- //! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers)
3+ //! See the [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers) repository
44//! for ciphers implementation.
55
66use crate :: block:: { BlockModeDecrypt , BlockModeEncrypt } ;
@@ -20,7 +20,7 @@ pub use errors::{OverflowError, StreamCipherError};
2020#[ cfg( feature = "stream-wrapper" ) ]
2121pub use wrapper:: StreamCipherCoreWrapper ;
2222
23- /// Marker trait for block-level asynchronous stream ciphers
23+ /// Asynchronous stream cipher trait.
2424pub trait AsyncStreamCipher : Sized {
2525 /// Encrypt data using `InOutBuf`.
2626 fn encrypt_inout ( mut self , data : InOutBuf < ' _ , ' _ , u8 > )
@@ -86,34 +86,127 @@ pub trait AsyncStreamCipher: Sized {
8686 }
8787}
8888
89- /// Synchronous stream cipher core trait.
89+ /// Stream cipher trait.
90+ ///
91+ /// This trait applies only to synchronous stream ciphers, which generate a keystream and
92+ /// XOR data with it during both encryption and decryption. Therefore, instead of separate methods
93+ /// for encryption and decryption, this trait provides methods for keystream application.
94+ ///
95+ /// # Notes on Keystream Repetition
96+ /// All stream ciphers have a finite state, so the generated keystream inevitably repeats itself,
97+ /// making the cipher vulnerable to chosen plaintext attack. Typically, the repetition period is
98+ /// astronomically large, rendering keystream repetition impossible to encounter in practice.
99+ ///
100+ /// However, counter-based stream ciphers allow seeking across the keystream, and some also use
101+ /// small counters (e.g. 32 bits). This can result in triggering keystream repetition in practice.
102+ ///
103+ /// To guard against this, methods either panic (e.g. [`StreamCipher::apply_keystream`]) or
104+ /// return [`StreamCipherError`] (e.g. [`StreamCipher::try_apply_keystream`]) when
105+ /// keystream repetition occurs. We also provide a number of "unchecked" methods
106+ /// (e.g. [`StreamCipher::unchecked_apply_keystream`]), but they should be used with extreme care.
107+ ///
108+ /// For efficiency reasons, the check for keystream repetition is typically implemented by
109+ /// forbidding the generation of the last keystream block in both the keystream application methods
110+ /// and the seeking methods defined in the [`StreamCipherSeek`] trait.
90111pub trait StreamCipher {
112+ /// Check that the cipher can generate a keystream with a length of `data_len` bytes.
113+ fn check_remaining ( & self , data_len : usize ) -> Result < ( ) , StreamCipherError > ;
114+
115+ /// Apply keystream to `inout` without checking for keystream repetition.
116+ ///
117+ /// # WARNING
118+ /// This method should be used with extreme caution! Triggering keystream repetition can expose
119+ /// the stream cipher to chosen plaintext attacks.
120+ fn unchecked_apply_keystream_inout ( & mut self , buf : InOutBuf < ' _ , ' _ , u8 > ) ;
121+
122+ /// Apply keystream to `buf` without checking for keystream repetition.
123+ ///
124+ /// # WARNING
125+ /// This method should be used with extreme caution! Triggering keystream repetition can expose
126+ /// the stream cipher to chosen plaintext attacks.
127+ fn unchecked_write_keystream ( & mut self , buf : & mut [ u8 ] ) ;
128+
129+ /// Apply keystream to data behind `buf` without checking for keystream repetition.
130+ ///
131+ /// # WARNING
132+ /// This method should be used with extreme caution! Triggering keystream repetition can expose
133+ /// the stream cipher to chosen plaintext attacks.
134+ #[ inline]
135+ fn unchecked_apply_keystream ( & mut self , buf : & mut [ u8 ] ) {
136+ self . unchecked_apply_keystream_inout ( buf. into ( ) )
137+ }
138+
139+ /// Apply keystream to data buffer-to-buffer without checking for keystream repetition.
140+ ///
141+ /// It will XOR generated keystream with data from the `input` buffer
142+ /// and will write result to the `output` buffer.
143+ ///
144+ /// Returns [`NotEqualError`] if the `input` and `output` buffers have different lengths.
145+ ///
146+ /// # WARNING
147+ /// This method should be used with extreme caution! Triggering keystream repetition can expose
148+ /// the stream cipher to chosen plaintext attacks.
149+ #[ inline]
150+ fn unchecked_apply_keystream_b2b (
151+ & mut self ,
152+ input : & [ u8 ] ,
153+ output : & mut [ u8 ] ,
154+ ) -> Result < ( ) , NotEqualError > {
155+ let buf = InOutBuf :: new ( input, output) ?;
156+ self . unchecked_apply_keystream_inout ( buf) ;
157+ Ok ( ( ) )
158+ }
159+
91160 /// Apply keystream to `inout` data.
92161 ///
93- /// If end of the keystream will be achieved with the given data length,
94- /// method will return [`StreamCipherError`] without modifying provided `data `.
162+ /// If the end of the keystream is reached with the given buffer length,
163+ /// the method will return [`StreamCipherError`] without modifying `buf `.
95164 fn try_apply_keystream_inout (
96165 & mut self ,
97166 buf : InOutBuf < ' _ , ' _ , u8 > ,
98- ) -> Result < ( ) , StreamCipherError > ;
167+ ) -> Result < ( ) , StreamCipherError > {
168+ self . check_remaining ( buf. len ( ) ) ?;
169+ self . unchecked_apply_keystream_inout ( buf) ;
170+ Ok ( ( ) )
171+ }
99172
100173 /// Apply keystream to data behind `buf`.
101174 ///
102- /// If end of the keystream will be achieved with the given data length,
103- /// method will return [`StreamCipherError`] without modifying provided `data `.
175+ /// If the end of the keystream is reached with the given buffer length,
176+ /// the method will return [`StreamCipherError`] without modifying `buf `.
104177 #[ inline]
105178 fn try_apply_keystream ( & mut self , buf : & mut [ u8 ] ) -> Result < ( ) , StreamCipherError > {
106179 self . try_apply_keystream_inout ( buf. into ( ) )
107180 }
108181
182+ /// Apply keystream to data buffer-to-buffer.
183+ ///
184+ /// It will XOR generated keystream with data from the `input` buffer
185+ /// and will write result to the `output` buffer.
186+ ///
187+ /// Returns [`StreamCipherError`] without modifying the buffers if the `input` and `output`
188+ /// buffers have different lengths, or if the end of the keystream is reached with
189+ /// the given data length.
190+ #[ inline]
191+ fn try_apply_keystream_b2b (
192+ & mut self ,
193+ input : & [ u8 ] ,
194+ output : & mut [ u8 ] ,
195+ ) -> Result < ( ) , StreamCipherError > {
196+ InOutBuf :: new ( input, output)
197+ . map_err ( |_| StreamCipherError )
198+ . and_then ( |buf| self . try_apply_keystream_inout ( buf) )
199+ }
200+
109201 /// Write keystream to `buf`.
110202 ///
111- /// If end of the keystream will be achieved with the given data length,
112- /// method will return [`StreamCipherError`] without modifying provided `data `.
203+ /// If the end of the keystream is reached with the given buffer length,
204+ /// the method will return [`StreamCipherError`] without modifying `buf `.
113205 #[ inline]
114206 fn try_write_keystream ( & mut self , buf : & mut [ u8 ] ) -> Result < ( ) , StreamCipherError > {
115- buf. fill ( 0 ) ;
116- self . try_apply_keystream ( buf)
207+ self . check_remaining ( buf. len ( ) ) ?;
208+ self . unchecked_write_keystream ( buf) ;
209+ Ok ( ( ) )
117210 }
118211
119212 /// Apply keystream to `inout` data.
@@ -122,8 +215,7 @@ pub trait StreamCipher {
122215 /// and will write result to `out` pointer.
123216 ///
124217 /// # Panics
125- /// If end of the keystream will be reached with the given data length,
126- /// method will panic without modifying the provided `data`.
218+ /// If the end of the keystream is reached with the given buffer length.
127219 #[ inline]
128220 fn apply_keystream_inout ( & mut self , buf : InOutBuf < ' _ , ' _ , u8 > ) {
129221 self . try_apply_keystream_inout ( buf) . unwrap ( ) ;
@@ -135,84 +227,84 @@ pub trait StreamCipher {
135227 /// to the same buffer.
136228 ///
137229 /// # Panics
138- /// If end of the keystream will be reached with the given data length,
139- /// method will panic without modifying the provided `data`.
230+ /// If the end of the keystream is reached with the given buffer length.
140231 #[ inline]
141232 fn apply_keystream ( & mut self , buf : & mut [ u8 ] ) {
142233 self . try_apply_keystream ( buf) . unwrap ( ) ;
143234 }
144235
145- /// Write keystream to `buf`.
236+ /// Apply keystream to data buffer-to-buffer.
237+ ///
238+ /// It will XOR generated keystream with data from the `input` buffer
239+ /// and will write result to the `output` buffer.
146240 ///
147241 /// # Panics
148- /// If end of the keystream will be reached with the given data length,
149- /// method will panic without modifying the provided `data` .
242+ /// If the end of the keystream is reached with the given buffer length,
243+ /// of if the `input` and `output` buffers have different lengths .
150244 #[ inline]
151- fn write_keystream ( & mut self , buf : & mut [ u8 ] ) {
152- self . try_write_keystream ( buf) . unwrap ( ) ;
245+ fn apply_keystream_b2b ( & mut self , input : & [ u8 ] , output : & mut [ u8 ] ) {
246+ let Ok ( buf) = InOutBuf :: new ( input, output) else {
247+ panic ! ( "Lengths of input and output buffers are not equal to each other!" ) ;
248+ } ;
249+ self . apply_keystream_inout ( buf)
153250 }
154251
155- /// Apply keystream to data buffer-to-buffer.
156- ///
157- /// It will XOR generated keystream with data from the `input` buffer
158- /// and will write result to the `output` buffer.
252+ /// Write keystream to `buf`.
159253 ///
160- /// Returns [`StreamCipherError`] if provided `in_blocks` and `out_blocks`
161- /// have different lengths or if end of the keystream will be reached with
162- /// the given input data length.
254+ /// # Panics
255+ /// If the end of the keystream is reached with the given buffer length.
163256 #[ inline]
164- fn apply_keystream_b2b (
165- & mut self ,
166- input : & [ u8 ] ,
167- output : & mut [ u8 ] ,
168- ) -> Result < ( ) , StreamCipherError > {
169- InOutBuf :: new ( input, output)
170- . map_err ( |_| StreamCipherError )
171- . and_then ( |buf| self . try_apply_keystream_inout ( buf) )
257+ fn write_keystream ( & mut self , buf : & mut [ u8 ] ) {
258+ self . try_write_keystream ( buf) . unwrap ( ) ;
172259 }
173260}
174261
175262/// Trait for seekable stream ciphers.
176263///
177- /// Methods of this trait are generic over the [`SeekNum`] trait, which is
178- /// implemented for primitive numeric types, i.e.: `i32`, `u32`, `u64`,
179- /// `u128`, and `usize`.
264+ /// Methods of this trait are generic over the [`SeekNum`] trait,
265+ /// i.e. they can be used with `i32`, `u32`, `u64`, `u128`, and `usize`.
180266pub trait StreamCipherSeek {
181- /// Try to get current keystream position
267+ /// Try to get current keystream position in bytes.
182268 ///
183- /// Returns [`OverflowError`] if position can not be represented by type `T`
269+ /// Returns [`OverflowError`] if the position value can not be represented by type `T`.
184270 fn try_current_pos < T : SeekNum > ( & self ) -> Result < T , OverflowError > ;
185271
186- /// Try to seek to the given position
272+ /// Try to seek to the provided position in bytes.
187273 ///
188- /// Returns [`StreamCipherError`] if provided position value is bigger than
189- /// keystream length.
274+ /// Returns [`StreamCipherError`] if the position value is bigger than keystream length.
190275 fn try_seek < T : SeekNum > ( & mut self , pos : T ) -> Result < ( ) , StreamCipherError > ;
191276
192- /// Get current keystream position
277+ /// Get current keystream position in bytes.
193278 ///
194279 /// # Panics
195- /// If position can not be represented by type `T`
280+ /// If the position value can not be represented by type `T`.
196281 fn current_pos < T : SeekNum > ( & self ) -> T {
197282 self . try_current_pos ( ) . unwrap ( )
198283 }
199284
200- /// Seek to the given position
285+ /// Seek to the provided keystream position in bytes.
201286 ///
202287 /// # Panics
203- /// If provided position value is bigger than keystream length
288+ /// If the position value is bigger than keystream length.
204289 fn seek < T : SeekNum > ( & mut self , pos : T ) {
205290 self . try_seek ( pos) . unwrap ( )
206291 }
207292}
208293
209294impl < C : StreamCipher > StreamCipher for & mut C {
210295 #[ inline]
211- fn try_apply_keystream_inout (
212- & mut self ,
213- buf : InOutBuf < ' _ , ' _ , u8 > ,
214- ) -> Result < ( ) , StreamCipherError > {
215- C :: try_apply_keystream_inout ( self , buf)
296+ fn check_remaining ( & self , data_len : usize ) -> Result < ( ) , StreamCipherError > {
297+ C :: check_remaining ( self , data_len)
298+ }
299+
300+ #[ inline]
301+ fn unchecked_apply_keystream_inout ( & mut self , buf : InOutBuf < ' _ , ' _ , u8 > ) {
302+ C :: unchecked_apply_keystream_inout ( self , buf)
303+ }
304+
305+ #[ inline]
306+ fn unchecked_write_keystream ( & mut self , buf : & mut [ u8 ] ) {
307+ C :: unchecked_write_keystream ( self , buf)
216308 }
217309}
218310
@@ -249,8 +341,8 @@ macro_rules! impl_seek_num {
249341 }
250342
251343 fn into_block_byte<T : StreamCipherCounter >( self , block_size: u8 ) -> Result <( T , u8 ) , OverflowError > {
252- let bs: Self = block_size . into ( ) ;
253- let byte = ( self % bs) as u8 ;
344+ let bs = Self :: from ( block_size ) ;
345+ let byte = u8 :: try_from ( self % bs) . expect ( "bs fits into u8" ) ;
254346 let block = T :: try_from( self / bs) . map_err( |_| OverflowError ) ?;
255347 Ok ( ( block, byte) )
256348 }
0 commit comments