@@ -3,7 +3,9 @@ use super::{
3
3
StreamCipherSeekCore , errors:: StreamCipherError ,
4
4
} ;
5
5
use core:: fmt;
6
- use crypto_common:: { Iv , IvSizeUser , Key , KeyInit , KeyIvInit , KeySizeUser , typenum:: Unsigned } ;
6
+ use crypto_common:: {
7
+ Iv , IvSizeUser , Key , KeyInit , KeyIvInit , KeySizeUser , array:: Array , typenum:: Unsigned ,
8
+ } ;
7
9
use inout:: InOutBuf ;
8
10
#[ cfg( feature = "zeroize" ) ]
9
11
use zeroize:: { Zeroize , ZeroizeOnDrop } ;
@@ -170,6 +172,58 @@ impl<T: StreamCipherCore> StreamCipher for StreamCipherCoreWrapper<T> {
170
172
171
173
Ok ( ( ) )
172
174
}
175
+
176
+ #[ inline]
177
+ fn try_write_keystream ( & mut self , mut data : & mut [ u8 ] ) -> Result < ( ) , StreamCipherError > {
178
+ self . check_remaining ( data. len ( ) ) ?;
179
+
180
+ let pos = usize:: from ( self . get_pos ( ) ) ;
181
+ let rem = usize:: from ( self . remaining ( ) ) ;
182
+ let data_len = data. len ( ) ;
183
+
184
+ if rem != 0 {
185
+ if data_len <= rem {
186
+ data. copy_from_slice ( & self . buffer [ pos..] [ ..data_len] ) ;
187
+ // SAFETY: we have checked that `data_len` is less or equal to length
188
+ // of remaining keystream data, thus `pos + data_len` can not be bigger
189
+ // than block size. Since `pos` is never zero, `pos + data_len` can not
190
+ // be zero. Thus `pos + data_len` satisfies the safety invariant required
191
+ // by `set_pos_unchecked`.
192
+ unsafe {
193
+ self . set_pos_unchecked ( pos + data_len) ;
194
+ }
195
+ return Ok ( ( ) ) ;
196
+ }
197
+ let ( left, right) = data. split_at_mut ( rem) ;
198
+ data = right;
199
+ left. copy_from_slice ( & self . buffer [ pos..] ) ;
200
+ }
201
+
202
+ let ( blocks, tail) = Array :: slice_as_chunks_mut ( data) ;
203
+ self . core . write_keystream_blocks ( blocks) ;
204
+
205
+ let new_pos = if tail. is_empty ( ) {
206
+ T :: BlockSize :: USIZE
207
+ } else {
208
+ // Note that we temporarily write a pseudo-random byte into
209
+ // the first byte of `self.buffer`. It may break the safety invariant,
210
+ // but after writing keystream block with `tail`, we immediately
211
+ // overwrite the first byte with a correct value.
212
+ self . core . write_keystream_block ( & mut self . buffer ) ;
213
+ tail. copy_from_slice ( & self . buffer [ ..tail. len ( ) ] ) ;
214
+ tail. len ( )
215
+ } ;
216
+
217
+ // SAFETY: `into_chunks` always returns tail with size
218
+ // less than block size. If `tail.len()` is zero, we replace
219
+ // it with block size. Thus the invariant required by
220
+ // `set_pos_unchecked` is satisfied.
221
+ unsafe {
222
+ self . set_pos_unchecked ( new_pos) ;
223
+ }
224
+
225
+ Ok ( ( ) )
226
+ }
173
227
}
174
228
175
229
impl < T : StreamCipherSeekCore > StreamCipherSeek for StreamCipherCoreWrapper < T > {
0 commit comments