@@ -151,6 +151,17 @@ 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. Panics if `key`'s len is not 32 bytes or `nonce`'s len
155
+ /// is not 16 bytes.
156
+ pub fn get_single_block ( key : & [ u8 ] , nonce : & [ u8 ] ) -> [ u8 ; 32 ] {
157
+ assert ! ( key. len( ) == 32 ) ;
158
+ assert ! ( nonce. len( ) == 16 ) ;
159
+ let mut chacha = ChaCha20 { state : ChaCha20 :: expand ( key, nonce) , output : [ 0u8 ; BLOCK_SIZE ] , offset : 64 } ;
160
+ let mut chacha_bytes = [ 0 ; 32 ] ;
161
+ chacha. process_in_place ( & mut chacha_bytes) ;
162
+ chacha_bytes
163
+ }
164
+
154
165
fn expand ( key : & [ u8 ] , nonce : & [ u8 ] ) -> ChaChaState {
155
166
let constant = match key. len ( ) {
156
167
16 => b"expand 16-byte k" ,
@@ -256,6 +267,16 @@ mod real_chacha {
256
267
self . offset += count;
257
268
}
258
269
}
270
+
271
+ #[ cfg( test) ]
272
+ pub fn seek ( & mut self , block_offset : u32 , offset_in_block : usize ) -> Result < ( ) , ( ) > {
273
+ let u32x4( _, d2, d3, d4) = self . state . d ;
274
+ self . state . d = u32x4 ( block_offset, d2, d3, d4) ;
275
+ self . update ( ) ;
276
+ self . offset = offset_in_block;
277
+
278
+ Ok ( ( ) )
279
+ }
259
280
}
260
281
}
261
282
#[ cfg( not( feature = "fuzztarget" ) ) ]
@@ -272,6 +293,12 @@ mod fuzzy_chacha {
272
293
Self { }
273
294
}
274
295
296
+ pub fn get_single_block ( key : & [ u8 ] , nonce : & [ u8 ] ) -> [ u8 ; 32 ] {
297
+ assert ! ( key. len( ) == 32 ) ;
298
+ assert ! ( nonce. len( ) == 16 ) ;
299
+ [ 0 ; 32 ]
300
+ }
301
+
275
302
pub fn process ( & mut self , input : & [ u8 ] , output : & mut [ u8 ] ) {
276
303
output. copy_from_slice ( input) ;
277
304
}
@@ -302,6 +329,7 @@ mod test {
302
329
use core:: iter:: repeat;
303
330
304
331
use super :: ChaCha20 ;
332
+ use std:: convert:: TryInto ;
305
333
306
334
#[ test]
307
335
fn test_chacha20_256_tls_vectors ( ) {
@@ -572,4 +600,35 @@ mod test {
572
600
assert_eq ! ( output, tv. keystream) ;
573
601
}
574
602
}
603
+
604
+ #[ test]
605
+ fn get_single_block ( ) {
606
+ // Test that `get_single_block` is equivalent to getting a block from a 12-byte nonce from the
607
+ // counter offset given by the remaining 4 bytes.
608
+ let key = [
609
+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
610
+ 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ,
611
+ 0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 ,
612
+ 0x18 , 0x19 , 0x1a , 0x1b , 0x1c , 0x1d , 0x1e , 0x1f ,
613
+ ] ;
614
+ let nonce_12bytes = [
615
+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
616
+ 0x08 , 0x09 , 0x0a , 0x0b
617
+ ] ;
618
+ let counter_pos = [ 0x00 , 0x01 , 0x02 , 0x03 ] ;
619
+ let nonce_16bytes = [ // nonce_12bytes prefixed by counter_pos
620
+ 0x00 , 0x01 , 0x02 , 0x03 ,
621
+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
622
+ 0x08 , 0x09 , 0x0a , 0x0b
623
+ ] ;
624
+
625
+ // Initialize a ChaCha20 instance with its counter starting at 0.
626
+ let mut chacha20 = ChaCha20 :: new ( & key, & nonce_12bytes) ;
627
+ // Seek its counter to counter_pos.
628
+ chacha20. seek ( u32:: from_le_bytes ( counter_pos) . try_into ( ) . unwrap ( ) , 0 ) . unwrap ( ) ;
629
+ let mut block_bytes = [ 0 ; 32 ] ;
630
+ chacha20. process_in_place ( & mut block_bytes) ;
631
+
632
+ assert_eq ! ( ChaCha20 :: get_single_block( & key, & nonce_16bytes) , block_bytes) ;
633
+ }
575
634
}
0 commit comments