@@ -361,6 +361,95 @@ mod recprot {
361361 write ! ( f, "[NULL AEAD]" )
362362 }
363363 }
364+
365+ #[ cfg( test) ]
366+ #[ cfg_attr( coverage_nightly, coverage( off) ) ]
367+ mod tests {
368+ use super :: { AEAD_NULL_TAG , RecordProtection } ;
369+
370+ fn aead ( ) -> RecordProtection {
371+ RecordProtection { }
372+ }
373+
374+ #[ test]
375+ fn expansion ( ) {
376+ assert_eq ! ( aead( ) . expansion( ) , AEAD_NULL_TAG . len( ) ) ;
377+ }
378+
379+ #[ test]
380+ fn debug ( ) {
381+ assert_eq ! ( format!( "{:?}" , aead( ) ) , "[NULL AEAD]" ) ;
382+ }
383+
384+ #[ test]
385+ fn encrypt_decrypt_roundtrip ( ) {
386+ let a = aead ( ) ;
387+ let plaintext = b"hello world" ;
388+ let mut out = vec ! [ 0u8 ; plaintext. len( ) + a. expansion( ) ] ;
389+ let encrypted = a. encrypt ( 0 , b"aad" , plaintext, & mut out) . unwrap ( ) ;
390+ assert_eq ! ( encrypted. len( ) , plaintext. len( ) + a. expansion( ) ) ;
391+ assert_eq ! ( & encrypted[ ..plaintext. len( ) ] , plaintext) ;
392+ assert_eq ! ( & encrypted[ plaintext. len( ) ..] , AEAD_NULL_TAG ) ;
393+
394+ let mut dec_out = vec ! [ 0u8 ; plaintext. len( ) ] ;
395+ let decrypted = a. decrypt ( 0 , b"aad" , encrypted, & mut dec_out) . unwrap ( ) ;
396+ assert_eq ! ( decrypted, plaintext) ;
397+ }
398+
399+ #[ test]
400+ fn encrypt_in_place_roundtrip ( ) {
401+ let a = aead ( ) ;
402+ let plaintext = b"hello" ;
403+ let mut buf = plaintext. to_vec ( ) ;
404+ buf. resize ( plaintext. len ( ) + a. expansion ( ) , 0 ) ;
405+ let len = a. encrypt_in_place ( 0 , b"" , & mut buf) . unwrap ( ) ;
406+ assert_eq ! ( len, buf. len( ) ) ;
407+ assert_eq ! ( & buf[ plaintext. len( ) ..] , AEAD_NULL_TAG ) ;
408+
409+ let dec_len = a. decrypt_in_place ( 0 , b"" , & mut buf) . unwrap ( ) ;
410+ assert_eq ! ( dec_len, plaintext. len( ) ) ;
411+ assert_eq ! ( & buf[ ..dec_len] , plaintext) ;
412+ }
413+
414+ #[ test]
415+ fn decrypt_empty_plaintext ( ) {
416+ // Zero-length plaintext (just the tag) is valid.
417+ let a = aead ( ) ;
418+ let mut out = vec ! [ 0u8 ; a. expansion( ) ] ;
419+ a. encrypt ( 0 , b"" , b"" , & mut out) . unwrap ( ) ;
420+ let mut dec = vec ! [ ] ;
421+ let res = a. decrypt ( 0 , b"" , & out, & mut dec) . unwrap ( ) ;
422+ assert_eq ! ( res, b"" ) ;
423+ }
424+
425+ #[ test]
426+ fn decrypt_fails_too_short ( ) {
427+ let a = aead ( ) ;
428+ let short = & AEAD_NULL_TAG [ ..a. expansion ( ) - 1 ] ;
429+ assert ! ( a. decrypt( 0 , b"" , short, & mut [ ] ) . is_err( ) ) ;
430+ }
431+
432+ #[ test]
433+ fn decrypt_fails_bad_tag ( ) {
434+ let a = aead ( ) ;
435+ let plaintext = b"test" ;
436+ let mut buf = vec ! [ 0u8 ; plaintext. len( ) + a. expansion( ) ] ;
437+ a. encrypt ( 0 , b"" , plaintext, & mut buf) . unwrap ( ) ;
438+ // Corrupt the tag.
439+ let tag_start = plaintext. len ( ) ;
440+ buf[ tag_start] ^= 0xff ;
441+ assert ! ( a. decrypt( 0 , b"" , & buf, & mut [ ] ) . is_err( ) ) ;
442+ }
443+
444+ #[ test]
445+ fn decrypt_rejects_all_zero_data_bytes ( ) {
446+ // All-zero plaintext with correct tag should fail (looks like padding).
447+ let a = aead ( ) ;
448+ let mut buf = vec ! [ 0u8 ; 4 + a. expansion( ) ] ;
449+ buf[ 4 ..] . copy_from_slice ( AEAD_NULL_TAG ) ;
450+ assert ! ( a. decrypt( 0 , b"" , & buf, & mut [ ] ) . is_err( ) ) ;
451+ }
452+ }
364453}
365454
366455/// All the nonces are the same length. Exploit that.
0 commit comments