55 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" ,
66 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
77) ]
8- #![ deny( unsafe_code) ]
8+ // #![deny(unsafe_code)]
99#![ warn( missing_docs, rust_2018_idioms) ]
1010
1111/// Constants used, reexported for convenience.
@@ -21,11 +21,12 @@ pub use aead::{
2121use aead:: { PostfixTagged , array:: ArraySize } ;
2222use cipher:: {
2323 BlockCipherDecrypt , BlockCipherEncrypt , BlockSizeUser ,
24- consts:: { U12 , U16 } ,
24+ consts:: { U2 , U12 , U16 } ,
2525 typenum:: Unsigned ,
2626} ;
27- use core:: marker:: PhantomData ;
27+ use core:: { marker:: PhantomData , ops :: Mul } ;
2828use dbl:: Dbl ;
29+ use inout:: { InOut , InOutBuf } ;
2930use subtle:: ConstantTimeEq ;
3031
3132/// Number of L values to be precomputed. Precomputing m values, allows
@@ -55,7 +56,9 @@ pub type Nonce<NonceSize> = Array<u8, NonceSize>;
5556/// OCB3 tag
5657pub type Tag < TagSize > = Array < u8 , TagSize > ;
5758
58- pub ( crate ) type Block = Array < u8 , U16 > ;
59+ type BlockSize = U16 ;
60+ pub ( crate ) type Block = Array < u8 , BlockSize > ;
61+ type DoubleBlock = Array < u8 , <BlockSize as Mul < U2 > >:: Output > ;
5962
6063mod sealed {
6164 use aead:: array:: {
@@ -210,34 +213,36 @@ where
210213 associated_data : & [ u8 ] ,
211214 buffer : & mut [ u8 ] ,
212215 ) -> aead:: Result < aead:: Tag < Self > > {
216+ let buffer = InOutBuf :: from ( buffer) ;
213217 if ( buffer. len ( ) > P_MAX ) || ( associated_data. len ( ) > A_MAX ) {
214218 unimplemented ! ( )
215219 }
216220
217221 // First, try to process many blocks at once.
218- let ( processed_bytes , mut offset_i, mut checksum_i) = self . wide_encrypt ( nonce, buffer) ;
222+ let ( tail , index , mut offset_i, mut checksum_i) = self . wide_encrypt ( nonce, buffer) ;
219223
220- let mut i = ( processed_bytes / 16 ) + 1 ;
224+ let mut i = index ;
221225
222226 // Then, process the remaining blocks.
223- for p_i in Block :: slice_as_chunks_mut ( & mut buffer[ processed_bytes..] ) . 0 {
227+ let ( blocks, mut tail) : ( InOutBuf < ' _ , ' _ , Block > , _ ) = tail. into_chunks ( ) ;
228+
229+ for p_i in blocks {
224230 // offset_i = offset_{i-1} xor L_{ntz(i)}
225231 inplace_xor ( & mut offset_i, & self . ll [ ntz ( i) ] ) ;
226232 // checksum_i = checksum_{i-1} xor p_i
227- inplace_xor ( & mut checksum_i, p_i) ;
233+ inplace_xor ( & mut checksum_i, p_i. get_in ( ) ) ;
228234 // c_i = offset_i xor ENCIPHER(K, p_i xor offset_i)
229- let c_i = p_i;
230- inplace_xor ( c_i, & offset_i) ;
231- self . cipher . encrypt_block ( c_i) ;
232- inplace_xor ( c_i, & offset_i) ;
235+ let mut c_i = p_i;
236+ c_i. xor_in2out ( & offset_i) ;
237+ self . cipher . encrypt_block ( c_i. get_out ( ) ) ;
238+ inplace_xor ( c_i. get_out ( ) , & offset_i) ;
233239
234240 i += 1 ;
235241 }
236242
237243 // Process any partial blocks.
238- if ( buffer. len ( ) % 16 ) != 0 {
239- let processed_bytes = ( i - 1 ) * 16 ;
240- let remaining_bytes = buffer. len ( ) - processed_bytes;
244+ if !tail. is_empty ( ) {
245+ let remaining_bytes = tail. len ( ) ;
241246
242247 // offset_* = offset_m xor L_*
243248 inplace_xor ( & mut offset_i, & self . ll_star ) ;
@@ -247,15 +252,13 @@ where
247252 self . cipher . encrypt_block ( & mut pad) ;
248253 // checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
249254 let checksum_rhs = & mut [ 0u8 ; 16 ] ;
250- checksum_rhs[ ..remaining_bytes] . copy_from_slice ( & buffer [ processed_bytes.. ] ) ;
255+ checksum_rhs[ ..remaining_bytes] . copy_from_slice ( tail . get_in ( ) ) ;
251256 checksum_rhs[ remaining_bytes] = 0b1000_0000 ;
252257 inplace_xor ( & mut checksum_i, checksum_rhs. as_ref ( ) ) ;
253258 // C_* = P_* xor Pad[1..bitlen(P_*)]
254- let p_star = & mut buffer [ processed_bytes.. ] ;
259+ let p_star = tail . get_out ( ) ;
255260 let pad = & mut pad[ ..p_star. len ( ) ] ;
256- for ( aa, bb) in p_star. iter_mut ( ) . zip ( pad) {
257- * aa ^= * bb;
258- }
261+ tail. xor_in2out ( pad) ;
259262 }
260263
261264 let tag = self . compute_tag ( associated_data, & mut checksum_i, & offset_i) ;
@@ -295,32 +298,32 @@ where
295298 if ( buffer. len ( ) > C_MAX ) || ( associated_data. len ( ) > A_MAX ) {
296299 unimplemented ! ( )
297300 }
301+ let buffer = InOutBuf :: from ( buffer) ;
298302
299303 // First, try to process many blocks at once.
300- let ( processed_bytes , mut offset_i, mut checksum_i) = self . wide_decrypt ( nonce, buffer) ;
304+ let ( tail , index , mut offset_i, mut checksum_i) = self . wide_decrypt ( nonce, buffer) ;
301305
302- let mut i = ( processed_bytes / 16 ) + 1 ;
306+ let mut i = index ;
303307
304308 // Then, process the remaining blocks.
305- let ( blocks, _remaining ) = Block :: slice_as_chunks_mut ( & mut buffer [ processed_bytes.. ] ) ;
309+ let ( blocks, mut tail ) : ( InOutBuf < ' _ , ' _ , Block > , _ ) = tail . into_chunks ( ) ;
306310 for c_i in blocks {
307311 // offset_i = offset_{i-1} xor L_{ntz(i)}
308312 inplace_xor ( & mut offset_i, & self . ll [ ntz ( i) ] ) ;
309313 // p_i = offset_i xor DECIPHER(K, c_i xor offset_i)
310- let p_i = c_i;
311- inplace_xor ( p_i, & offset_i) ;
312- self . cipher . decrypt_block ( p_i) ;
313- inplace_xor ( p_i, & offset_i) ;
314+ let mut p_i = c_i;
315+ p_i. xor_in2out ( & offset_i) ;
316+ self . cipher . decrypt_block ( p_i. get_out ( ) ) ;
317+ inplace_xor ( p_i. get_out ( ) , & offset_i) ;
314318 // checksum_i = checksum_{i-1} xor p_i
315- inplace_xor ( & mut checksum_i, p_i) ;
319+ inplace_xor ( & mut checksum_i, p_i. get_out ( ) ) ;
316320
317321 i += 1 ;
318322 }
319323
320324 // Process any partial blocks.
321- if ( buffer. len ( ) % 16 ) != 0 {
322- let processed_bytes = ( i - 1 ) * 16 ;
323- let remaining_bytes = buffer. len ( ) - processed_bytes;
325+ if !tail. is_empty ( ) {
326+ let remaining_bytes = tail. len ( ) ;
324327
325328 // offset_* = offset_m xor L_*
326329 inplace_xor ( & mut offset_i, & self . ll_star ) ;
@@ -329,14 +332,12 @@ where
329332 inplace_xor ( & mut pad, & offset_i) ;
330333 self . cipher . encrypt_block ( & mut pad) ;
331334 // P_* = C_* xor Pad[1..bitlen(C_*)]
332- let c_star = & mut buffer [ processed_bytes.. ] ;
335+ let c_star = tail . get_in ( ) ;
333336 let pad = & mut pad[ ..c_star. len ( ) ] ;
334- for ( aa, bb) in c_star. iter_mut ( ) . zip ( pad) {
335- * aa ^= * bb;
336- }
337+ tail. xor_in2out ( pad) ;
337338 // checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
338339 let checksum_rhs = & mut [ 0u8 ; 16 ] ;
339- checksum_rhs[ ..remaining_bytes] . copy_from_slice ( & buffer [ processed_bytes.. ] ) ;
340+ checksum_rhs[ ..remaining_bytes] . copy_from_slice ( tail . get_out ( ) ) ;
340341 checksum_rhs[ remaining_bytes] = 0b1000_0000 ;
341342 inplace_xor ( & mut checksum_i, checksum_rhs. as_ref ( ) ) ;
342343 }
@@ -347,20 +348,25 @@ where
347348 /// Encrypts plaintext in groups of two.
348349 ///
349350 /// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c
350- fn wide_encrypt ( & self , nonce : & Nonce < NonceSize > , buffer : & mut [ u8 ] ) -> ( usize , Block , Block ) {
351+ fn wide_encrypt < ' i , ' o > (
352+ & self ,
353+ nonce : & Nonce < NonceSize > ,
354+ buffer : InOutBuf < ' i , ' o , u8 > ,
355+ ) -> ( InOutBuf < ' i , ' o , u8 > , usize , Block , Block ) {
351356 const WIDTH : usize = 2 ;
352357
353358 let mut i = 1 ;
354359
355360 let mut offset_i = [ Block :: default ( ) ; WIDTH ] ;
356361 offset_i[ offset_i. len ( ) - 1 ] = initial_offset ( & self . cipher , nonce, TagSize :: to_u32 ( ) ) ;
357362 let mut checksum_i = Block :: default ( ) ;
358- for wide_blocks in buffer. chunks_exact_mut ( <Block as AssocArraySize >:: Size :: USIZE * WIDTH ) {
359- let p_i = split_into_two_blocks ( wide_blocks) ;
360363
364+ let ( wide_blocks, tail) : ( InOutBuf < ' _ , ' _ , DoubleBlock > , _ ) = buffer. into_chunks ( ) ;
365+ for wide_block in wide_blocks. into_iter ( ) {
366+ let mut p_i = split_into_two_blocks ( wide_block) ;
361367 // checksum_i = checksum_{i-1} xor p_i
362368 for p_ij in & p_i {
363- inplace_xor ( & mut checksum_i, p_ij) ;
369+ inplace_xor ( & mut checksum_i, p_ij. get_in ( ) ) ;
364370 }
365371
366372 // offset_i = offset_{i-1} xor L_{ntz(i)}
@@ -373,32 +379,36 @@ where
373379
374380 // c_i = offset_i xor ENCIPHER(K, p_i xor offset_i)
375381 for j in 0 ..p_i. len ( ) {
376- inplace_xor ( p_i[ j] , & offset_i[ j] ) ;
377- self . cipher . encrypt_block ( p_i[ j] ) ;
378- inplace_xor ( p_i[ j] , & offset_i[ j] )
382+ p_i[ j] . xor_in2out ( & offset_i[ j] ) ;
383+ self . cipher . encrypt_block ( p_i[ j] . get_out ( ) ) ;
384+ inplace_xor ( p_i[ j] . get_out ( ) , & offset_i[ j] ) ;
379385 }
380386
381387 i += WIDTH ;
382388 }
383389
384- let processed_bytes = ( buffer. len ( ) / ( WIDTH * 16 ) ) * ( WIDTH * 16 ) ;
385-
386- ( processed_bytes, offset_i[ offset_i. len ( ) - 1 ] , checksum_i)
390+ ( tail, i, offset_i[ offset_i. len ( ) - 1 ] , checksum_i)
387391 }
388392
389393 /// Decrypts plaintext in groups of two.
390394 ///
391395 /// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c
392- fn wide_decrypt ( & self , nonce : & Nonce < NonceSize > , buffer : & mut [ u8 ] ) -> ( usize , Block , Block ) {
396+ fn wide_decrypt < ' i , ' o > (
397+ & self ,
398+ nonce : & Nonce < NonceSize > ,
399+ buffer : InOutBuf < ' i , ' o , u8 > ,
400+ ) -> ( InOutBuf < ' i , ' o , u8 > , usize , Block , Block ) {
393401 const WIDTH : usize = 2 ;
394402
395403 let mut i = 1 ;
396404
397405 let mut offset_i = [ Block :: default ( ) ; WIDTH ] ;
398406 offset_i[ offset_i. len ( ) - 1 ] = initial_offset ( & self . cipher , nonce, TagSize :: to_u32 ( ) ) ;
399407 let mut checksum_i = Block :: default ( ) ;
400- for wide_blocks in buffer. chunks_exact_mut ( 16 * WIDTH ) {
401- let c_i = split_into_two_blocks ( wide_blocks) ;
408+
409+ let ( wide_blocks, tail) : ( InOutBuf < ' _ , ' _ , DoubleBlock > , _ ) = buffer. into_chunks ( ) ;
410+ for wide_block in wide_blocks. into_iter ( ) {
411+ let mut c_i = split_into_two_blocks ( wide_block) ;
402412
403413 // offset_i = offset_{i-1} xor L_{ntz(i)}
404414 offset_i[ 0 ] = offset_i[ offset_i. len ( ) - 1 ] ;
@@ -411,17 +421,16 @@ where
411421 // p_i = offset_i xor DECIPHER(K, c_i xor offset_i)
412422 // checksum_i = checksum_{i-1} xor p_i
413423 for j in 0 ..c_i. len ( ) {
414- inplace_xor ( c_i[ j] , & offset_i[ j] ) ;
415- self . cipher . decrypt_block ( c_i[ j] ) ;
416- inplace_xor ( c_i[ j] , & offset_i[ j] ) ;
417- inplace_xor ( & mut checksum_i, c_i[ j] ) ;
424+ c_i[ j] . xor_in2out ( & offset_i[ j] ) ;
425+ self . cipher . decrypt_block ( c_i[ j] . get_out ( ) ) ;
426+ inplace_xor ( c_i[ j] . get_out ( ) , & offset_i[ j] ) ;
427+ inplace_xor ( & mut checksum_i, c_i[ j] . get_out ( ) ) ;
418428 }
419429
420430 i += WIDTH ;
421431 }
422432
423- let processed_bytes = ( buffer. len ( ) / ( WIDTH * 16 ) ) * ( WIDTH * 16 ) ;
424- ( processed_bytes, offset_i[ offset_i. len ( ) - 1 ] , checksum_i)
433+ ( tail, i, offset_i[ offset_i. len ( ) - 1 ] , checksum_i)
425434 }
426435
427436 /// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1
@@ -580,11 +589,20 @@ pub(crate) fn ntz(n: usize) -> usize {
580589}
581590
582591#[ inline]
583- pub ( crate ) fn split_into_two_blocks ( two_blocks : & mut [ u8 ] ) -> [ & mut Block ; 2 ] {
584- const BLOCK_SIZE : usize = 16 ;
585- debug_assert_eq ! ( two_blocks. len( ) , BLOCK_SIZE * 2 ) ;
586- let ( b0, b1) = two_blocks. split_at_mut ( BLOCK_SIZE ) ;
587- [ b0. try_into ( ) . unwrap ( ) , b1. try_into ( ) . unwrap ( ) ]
592+ pub ( crate ) fn split_into_two_blocks < ' i , ' o > (
593+ two_blocks : InOut < ' i , ' o , DoubleBlock > ,
594+ ) -> [ InOut < ' i , ' o , Block > ; 2 ] {
595+ let ( input, output) = two_blocks. into_raw ( ) ;
596+
597+ let ( bi0, bi1) = unsafe { input. as_ref ( ) }
598+ . unwrap ( )
599+ . split_at ( BlockSize :: USIZE ) ;
600+ let ( bi0, bi1) : ( & Block , & Block ) = ( bi0. try_into ( ) . unwrap ( ) , bi1. try_into ( ) . unwrap ( ) ) ;
601+ let ( bo0, bo1) = unsafe { output. as_mut ( ) }
602+ . unwrap ( )
603+ . split_at_mut ( BlockSize :: USIZE ) ;
604+ let ( bo0, bo1) : ( & mut Block , & mut Block ) = ( bo0. try_into ( ) . unwrap ( ) , bo1. try_into ( ) . unwrap ( ) ) ;
605+ [ InOut :: from ( ( bi0, bo0) ) , InOut :: from ( ( bi1, bo1) ) ]
588606}
589607
590608#[ cfg( test) ]
0 commit comments