@@ -25,8 +25,8 @@ enum Cipher {
2525 Aes128Ecb ( Box < ecb:: Encryptor < aes:: Aes128 > > ) ,
2626 Aes192Ecb ( Box < ecb:: Encryptor < aes:: Aes192 > > ) ,
2727 Aes256Ecb ( Box < ecb:: Encryptor < aes:: Aes256 > > ) ,
28- Aes128Gcm ( Box < Aes128Gcm > ) ,
29- Aes256Gcm ( Box < Aes256Gcm > ) ,
28+ Aes128Gcm ( Box < Aes128Gcm > , Option < usize > ) ,
29+ Aes256Gcm ( Box < Aes256Gcm > , Option < usize > ) ,
3030 Aes256Cbc ( Box < cbc:: Encryptor < aes:: Aes256 > > ) ,
3131 Aes128Ctr ( Box < ctr:: Ctr128BE < aes:: Aes128 > > ) ,
3232 Aes192Ctr ( Box < ctr:: Ctr128BE < aes:: Aes192 > > ) ,
@@ -74,9 +74,15 @@ impl CipherContext {
7474 algorithm : & str ,
7575 key : & [ u8 ] ,
7676 iv : & [ u8 ] ,
77+ auth_tag_length : Option < usize > ,
7778 ) -> Result < Self , CipherContextError > {
7879 Ok ( Self {
79- cipher : Rc :: new ( RefCell :: new ( Cipher :: new ( algorithm, key, iv) ?) ) ,
80+ cipher : Rc :: new ( RefCell :: new ( Cipher :: new (
81+ algorithm,
82+ key,
83+ iv,
84+ auth_tag_length,
85+ ) ?) ) ,
8086 } )
8187 }
8288
@@ -197,13 +203,17 @@ pub enum CipherError {
197203 #[ class( type ) ]
198204 #[ error( "Unknown cipher {0}" ) ]
199205 UnknownCipher ( String ) ,
206+ #[ class( type ) ]
207+ #[ error( "Invalid authentication tag length: {0}" ) ]
208+ InvalidAuthTag ( usize ) ,
200209}
201210
202211impl Cipher {
203212 fn new (
204213 algorithm_name : & str ,
205214 key : & [ u8 ] ,
206215 iv : & [ u8 ] ,
216+ auth_tag_length : Option < usize > ,
207217 ) -> Result < Self , CipherError > {
208218 use Cipher :: * ;
209219 Ok ( match algorithm_name {
@@ -218,20 +228,32 @@ impl Cipher {
218228 return Err ( CipherError :: InvalidKeyLength ) ;
219229 }
220230
231+ if let Some ( tag_len) = auth_tag_length
232+ && !is_valid_gcm_tag_length ( tag_len)
233+ {
234+ return Err ( CipherError :: InvalidAuthTag ( tag_len) ) ;
235+ }
236+
221237 let cipher =
222238 aead_gcm_stream:: AesGcm :: < aes:: Aes128 > :: new ( key. into ( ) , iv) ;
223239
224- Aes128Gcm ( Box :: new ( cipher) )
240+ Aes128Gcm ( Box :: new ( cipher) , auth_tag_length )
225241 }
226242 "aes-256-gcm" => {
227243 if key. len ( ) != aes:: Aes256 :: key_size ( ) {
228244 return Err ( CipherError :: InvalidKeyLength ) ;
229245 }
230246
247+ if let Some ( tag_len) = auth_tag_length
248+ && !is_valid_gcm_tag_length ( tag_len)
249+ {
250+ return Err ( CipherError :: InvalidAuthTag ( tag_len) ) ;
251+ }
252+
231253 let cipher =
232254 aead_gcm_stream:: AesGcm :: < aes:: Aes256 > :: new ( key. into ( ) , iv) ;
233255
234- Aes256Gcm ( Box :: new ( cipher) )
256+ Aes256Gcm ( Box :: new ( cipher) , auth_tag_length )
235257 }
236258 "aes256" | "aes-256-cbc" => {
237259 if key. len ( ) != 32 {
@@ -277,10 +299,10 @@ impl Cipher {
277299 fn set_aad ( & mut self , aad : & [ u8 ] ) {
278300 use Cipher :: * ;
279301 match self {
280- Aes128Gcm ( cipher) => {
302+ Aes128Gcm ( cipher, _ ) => {
281303 cipher. set_aad ( aad) ;
282304 }
283- Aes256Gcm ( cipher) => {
305+ Aes256Gcm ( cipher, _ ) => {
284306 cipher. set_aad ( aad) ;
285307 }
286308 _ => { }
@@ -315,11 +337,11 @@ impl Cipher {
315337 encryptor. encrypt_block_b2b_mut ( input. into ( ) , output. into ( ) ) ;
316338 }
317339 }
318- Aes128Gcm ( cipher) => {
340+ Aes128Gcm ( cipher, _ ) => {
319341 output[ ..input. len ( ) ] . copy_from_slice ( input) ;
320342 cipher. encrypt ( output) ;
321343 }
322- Aes256Gcm ( cipher) => {
344+ Aes256Gcm ( cipher, _ ) => {
323345 output[ ..input. len ( ) ] . copy_from_slice ( input) ;
324346 cipher. encrypt ( output) ;
325347 }
@@ -403,8 +425,20 @@ impl Cipher {
403425 ) ;
404426 Ok ( None )
405427 }
406- ( Aes128Gcm ( cipher) , _) => Ok ( Some ( cipher. finish ( ) . to_vec ( ) ) ) ,
407- ( Aes256Gcm ( cipher) , _) => Ok ( Some ( cipher. finish ( ) . to_vec ( ) ) ) ,
428+ ( Aes128Gcm ( cipher, auth_tag_length) , _) => {
429+ let mut tag = cipher. finish ( ) . to_vec ( ) ;
430+ if let Some ( tag_len) = auth_tag_length {
431+ tag. truncate ( tag_len) ;
432+ }
433+ Ok ( Some ( tag) )
434+ }
435+ ( Aes256Gcm ( cipher, auth_tag_length) , _) => {
436+ let mut tag = cipher. finish ( ) . to_vec ( ) ;
437+ if let Some ( tag_len) = auth_tag_length {
438+ tag. truncate ( tag_len) ;
439+ }
440+ Ok ( Some ( tag) )
441+ }
408442 ( Aes256Cbc ( encryptor) , true ) => {
409443 let _ = ( * encryptor)
410444 . encrypt_padded_b2b_mut :: < Pkcs7 > ( input, output)
@@ -425,8 +459,20 @@ impl Cipher {
425459 fn take_tag ( self ) -> Tag {
426460 use Cipher :: * ;
427461 match self {
428- Aes128Gcm ( cipher) => Some ( cipher. finish ( ) . to_vec ( ) ) ,
429- Aes256Gcm ( cipher) => Some ( cipher. finish ( ) . to_vec ( ) ) ,
462+ Aes128Gcm ( cipher, auth_tag_length) => {
463+ let mut tag = cipher. finish ( ) . to_vec ( ) ;
464+ if let Some ( tag_len) = auth_tag_length {
465+ tag. truncate ( tag_len) ;
466+ }
467+ Some ( tag)
468+ }
469+ Aes256Gcm ( cipher, auth_tag_length) => {
470+ let mut tag = cipher. finish ( ) . to_vec ( ) ;
471+ if let Some ( tag_len) = auth_tag_length {
472+ tag. truncate ( tag_len) ;
473+ }
474+ Some ( tag)
475+ }
430476 _ => None ,
431477 }
432478 }
@@ -760,9 +806,15 @@ impl Decipher {
760806 ) ;
761807 Ok ( ( ) )
762808 }
763- ( Aes128Gcm ( decipher, _ ) , true ) => {
809+ ( Aes128Gcm ( decipher, auth_tag_length ) , true ) => {
764810 let tag = decipher. finish ( ) ;
765- if tag. as_slice ( ) == auth_tag {
811+ let tag_slice = tag. as_slice ( ) ;
812+ let truncated_tag = if let Some ( len) = auth_tag_length {
813+ & tag_slice[ ..len]
814+ } else {
815+ tag_slice
816+ } ;
817+ if truncated_tag == auth_tag {
766818 Ok ( ( ) )
767819 } else {
768820 Err ( DecipherError :: DataAuthenticationFailed )
@@ -771,9 +823,15 @@ impl Decipher {
771823 ( Aes128Gcm ( ..) , false ) => {
772824 Err ( DecipherError :: SetAutoPaddingFalseAes128GcmUnsupported )
773825 }
774- ( Aes256Gcm ( decipher, _ ) , true ) => {
826+ ( Aes256Gcm ( decipher, auth_tag_length ) , true ) => {
775827 let tag = decipher. finish ( ) ;
776- if tag. as_slice ( ) == auth_tag {
828+ let tag_slice = tag. as_slice ( ) ;
829+ let truncated_tag = if let Some ( len) = auth_tag_length {
830+ & tag_slice[ ..len]
831+ } else {
832+ tag_slice
833+ } ;
834+ if truncated_tag == auth_tag {
777835 Ok ( ( ) )
778836 } else {
779837 Err ( DecipherError :: DataAuthenticationFailed )
0 commit comments