@@ -512,6 +512,15 @@ impl Aead {
512512 } )
513513 }
514514
515+ fn make_nonce ( nonce : & mut [ u8 ; NONCE_LEN ] , seq : SequenceNumber ) {
516+ for ( n, & s) in nonce[ NONCE_LEN - COUNTER_LEN ..]
517+ . iter_mut ( )
518+ . zip ( & seq. to_be_bytes ( ) )
519+ {
520+ * n ^= s;
521+ }
522+ }
523+
515524 pub fn import_key ( algorithm : AeadAlgorithms , key : & [ u8 ] ) -> Result < SymKey , Error > {
516525 let slot = p11:: Slot :: internal ( ) . map_err ( |_| Error :: Internal ) ?;
517526
@@ -590,6 +599,49 @@ impl Aead {
590599 Ok ( ct)
591600 }
592601
602+ /// Encrypt with an explicit sequence number. Mirrors `decrypt`'s nonce
603+ /// construction: the final nonce is `nonce_base XOR encode_be(seq)` over
604+ /// the trailing 8 bytes. The NSS PKCS#11 context's internal counter is
605+ /// not used (`CKG_NO_GENERATE`). The caller must never reuse
606+ /// `(nonce_base, seq)` with the same key.
607+ pub fn encrypt_with_seq (
608+ & mut self ,
609+ aad : & [ u8 ] ,
610+ seq : SequenceNumber ,
611+ pt : & [ u8 ] ,
612+ ) -> Result < Vec < u8 > , Error > {
613+ crate :: init ( ) ?;
614+
615+ assert_eq ! ( self . mode, Mode :: Encrypt ) ;
616+ let mut nonce = self . nonce_base ;
617+ Self :: make_nonce ( & mut nonce, seq) ;
618+ let mut ct = vec ! [ 0 ; pt. len( ) + TAG_LEN ] ;
619+ let mut ct_len: c_int = 0 ;
620+ let mut tag = vec ! [ 0 ; TAG_LEN ] ;
621+ secstatus_to_res ( unsafe {
622+ PK11_AEADOp (
623+ * self . ctx ,
624+ CK_GENERATOR_FUNCTION :: from ( CKG_NO_GENERATE ) ,
625+ c_int_len ( NONCE_LEN - COUNTER_LEN ) ?,
626+ nonce. as_mut_ptr ( ) ,
627+ c_int_len ( nonce. len ( ) ) ?,
628+ aad. as_ptr ( ) ,
629+ c_int_len ( aad. len ( ) ) ?,
630+ ct. as_mut_ptr ( ) ,
631+ & raw mut ct_len,
632+ c_int_len ( ct. len ( ) ) ?,
633+ tag. as_mut_ptr ( ) ,
634+ c_int_len ( tag. len ( ) ) ?,
635+ pt. as_ptr ( ) ,
636+ c_int_len ( pt. len ( ) ) ?,
637+ )
638+ } ) ?;
639+ ct. truncate ( usize:: try_from ( ct_len) . map_err ( |_| Error :: IntegerOverflow ) ?) ;
640+ debug_assert_eq ! ( ct. len( ) , pt. len( ) ) ;
641+ ct. append ( & mut tag) ;
642+ Ok ( ct)
643+ }
644+
593645 pub fn decrypt (
594646 & mut self ,
595647 aad : & [ u8 ] ,
@@ -600,9 +652,7 @@ impl Aead {
600652
601653 assert_eq ! ( self . mode, Mode :: Decrypt ) ;
602654 let mut nonce = self . nonce_base ;
603- for ( i, n) in nonce. iter_mut ( ) . rev ( ) . take ( COUNTER_LEN ) . enumerate ( ) {
604- * n ^= u8:: try_from ( ( seq >> ( 8 * i) ) & 0xff ) . map_err ( |_| Error :: IntegerOverflow ) ?;
605- }
655+ Self :: make_nonce ( & mut nonce, seq) ;
606656 let mut pt = vec ! [ 0 ; ct. len( ) ] ; // NSS needs more space than it uses for plaintext.
607657 let mut pt_len: c_int = 0 ;
608658 let pt_expected = ct. len ( ) . checked_sub ( TAG_LEN ) . ok_or ( Error :: AeadTruncated ) ?;
@@ -767,4 +817,39 @@ mod test {
767817 // Now use the real nonce and sequence number from the example.
768818 decrypt ( ALG , KEY , NONCE_BASE , 654_360_564 , AAD , PT , CT ) ;
769819 }
820+
821+ fn roundtrip_encrypt_with_seq ( algorithm : AeadAlgorithms , key : & [ u8 ] ) {
822+ const NONCE_BASE : [ u8 ; NONCE_LEN ] = [ 0 ; NONCE_LEN ] ;
823+ const AAD : & [ u8 ] = b"associated" ;
824+ const PT : & [ u8 ] = b"hello sframe" ;
825+ const SEQ : SequenceNumber = 0x0123_4567_89ab ;
826+
827+ fixture_init ( ) ;
828+
829+ let k = Aead :: import_key ( algorithm, key) . unwrap ( ) ;
830+ let mut enc = Aead :: new ( Mode :: Encrypt , algorithm, & k, NONCE_BASE ) . unwrap ( ) ;
831+ let ct = enc. encrypt_with_seq ( AAD , SEQ , PT ) . unwrap ( ) ;
832+
833+ let mut dec = Aead :: new ( Mode :: Decrypt , algorithm, & k, NONCE_BASE ) . unwrap ( ) ;
834+ let pt = dec. decrypt ( AAD , SEQ , & ct) . unwrap ( ) ;
835+ assert_eq ! ( & pt[ ..] , PT ) ;
836+ }
837+
838+ #[ test]
839+ fn encrypt_with_seq_aes128gcm ( ) {
840+ const KEY : & [ u8 ] = & [ 0x42 ; 16 ] ;
841+ roundtrip_encrypt_with_seq ( AeadAlgorithms :: Aes128Gcm , KEY ) ;
842+ }
843+
844+ #[ test]
845+ fn encrypt_with_seq_aes256gcm ( ) {
846+ const KEY : & [ u8 ] = & [ 0x42 ; 32 ] ;
847+ roundtrip_encrypt_with_seq ( AeadAlgorithms :: Aes256Gcm , KEY ) ;
848+ }
849+
850+ #[ test]
851+ fn encrypt_with_seq_chacha20poly1305 ( ) {
852+ const KEY : & [ u8 ] = & [ 0x42 ; 32 ] ;
853+ roundtrip_encrypt_with_seq ( AeadAlgorithms :: ChaCha20Poly1305 , KEY ) ;
854+ }
770855}
0 commit comments