@@ -151,6 +151,14 @@ mod real_chacha {
151
151
ChaCha20 { state : ChaCha20 :: expand ( key, nonce) , output : [ 0u8 ; BLOCK_SIZE ] , offset : 64 }
152
152
}
153
153
154
+ /// Get one block from a ChaCha stream.
155
+ pub fn get_single_block ( key : & [ u8 ; 32 ] , nonce : & [ u8 ; 16 ] ) -> [ u8 ; 32 ] {
156
+ let mut chacha = ChaCha20 { state : ChaCha20 :: expand ( key, nonce) , output : [ 0u8 ; BLOCK_SIZE ] , offset : 64 } ;
157
+ let mut chacha_bytes = [ 0 ; 32 ] ;
158
+ chacha. process_in_place ( & mut chacha_bytes) ;
159
+ chacha_bytes
160
+ }
161
+
154
162
fn expand ( key : & [ u8 ] , nonce : & [ u8 ] ) -> ChaChaState {
155
163
let constant = match key. len ( ) {
156
164
16 => b"expand 16-byte k" ,
@@ -256,6 +264,12 @@ mod real_chacha {
256
264
self . offset += count;
257
265
}
258
266
}
267
+
268
+ #[ cfg( test) ]
269
+ pub fn seek_to_block ( & mut self , block_offset : u32 ) {
270
+ self . state . d . 0 = block_offset;
271
+ self . update ( ) ;
272
+ }
259
273
}
260
274
}
261
275
#[ cfg( not( feature = "fuzztarget" ) ) ]
@@ -272,6 +286,10 @@ mod fuzzy_chacha {
272
286
Self { }
273
287
}
274
288
289
+ pub fn get_single_block ( _key : & [ u8 ; 32 ] , _nonce : & [ u8 ; 16 ] ) -> [ u8 ; 32 ] {
290
+ [ 0 ; 32 ]
291
+ }
292
+
275
293
pub fn process ( & mut self , input : & [ u8 ] , output : & mut [ u8 ] ) {
276
294
output. copy_from_slice ( input) ;
277
295
}
@@ -302,6 +320,7 @@ mod test {
302
320
use core:: iter:: repeat;
303
321
304
322
use super :: ChaCha20 ;
323
+ use std:: convert:: TryInto ;
305
324
306
325
#[ test]
307
326
fn test_chacha20_256_tls_vectors ( ) {
@@ -572,4 +591,31 @@ mod test {
572
591
assert_eq ! ( output, tv. keystream) ;
573
592
}
574
593
}
594
+
595
+ #[ test]
596
+ fn get_single_block ( ) {
597
+ // Test that `get_single_block` (which takes a 16-byte nonce) is equivalent to getting a block
598
+ // using a 12-byte nonce, with the block starting at the counter offset given by the remaining 4
599
+ // bytes.
600
+ let key = [
601
+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
602
+ 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ,
603
+ 0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 ,
604
+ 0x18 , 0x19 , 0x1a , 0x1b , 0x1c , 0x1d , 0x1e , 0x1f ,
605
+ ] ;
606
+ let nonce_16bytes = [
607
+ 0x00 , 0x01 , 0x02 , 0x03 , 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0a , 0x0b
608
+ ] ;
609
+ let counter_pos = & nonce_16bytes[ ..4 ] ;
610
+ let nonce_12bytes = & nonce_16bytes[ 4 ..] ;
611
+
612
+ // Initialize a ChaCha20 instance with its counter starting at 0.
613
+ let mut chacha20 = ChaCha20 :: new ( & key, nonce_12bytes) ;
614
+ // Seek its counter to the block at counter_pos.
615
+ chacha20. seek_to_block ( u32:: from_le_bytes ( counter_pos. try_into ( ) . unwrap ( ) ) ) ;
616
+ let mut block_bytes = [ 0 ; 32 ] ;
617
+ chacha20. process_in_place ( & mut block_bytes) ;
618
+
619
+ assert_eq ! ( ChaCha20 :: get_single_block( & key, & nonce_16bytes) , block_bytes) ;
620
+ }
575
621
}
0 commit comments