1717
1818//! Configuration and utilities for decryption of files using Parquet Modular Encryption
1919
20- use crate :: encryption:: ciphers:: { BlockDecryptor , RingGcmBlockDecryptor } ;
21- use crate :: encryption:: modules:: { create_module_aad, ModuleType } ;
20+ use crate :: encryption:: ciphers:: { BlockDecryptor , RingGcmBlockDecryptor , TAG_LEN } ;
21+ use crate :: encryption:: modules:: { create_footer_aad , create_module_aad, ModuleType } ;
2222use crate :: errors:: { ParquetError , Result } ;
2323use crate :: file:: column_crypto_metadata:: ColumnCryptoMetaData ;
2424use std:: borrow:: Cow ;
@@ -331,6 +331,7 @@ impl PartialEq for DecryptionKeys {
331331pub struct FileDecryptionProperties {
332332 keys : DecryptionKeys ,
333333 aad_prefix : Option < Vec < u8 > > ,
334+ footer_signature_verification : bool ,
334335}
335336
336337impl FileDecryptionProperties {
@@ -351,6 +352,11 @@ impl FileDecryptionProperties {
351352 self . aad_prefix . as_ref ( )
352353 }
353354
355+ /// Returns true if footer signature verification is enabled for files with plaintext footers.
356+ pub fn check_plaintext_footer_integrity ( & self ) -> bool {
357+ self . footer_signature_verification
358+ }
359+
354360 /// Get the encryption key for decrypting a file's footer,
355361 /// and also column data if uniform encryption is used.
356362 pub fn footer_key ( & self , key_metadata : Option < & [ u8 ] > ) -> Result < Cow < Vec < u8 > > > {
@@ -415,6 +421,7 @@ pub struct DecryptionPropertiesBuilder {
415421 key_retriever : Option < Arc < dyn KeyRetriever > > ,
416422 column_keys : HashMap < String , Vec < u8 > > ,
417423 aad_prefix : Option < Vec < u8 > > ,
424+ footer_signature_verification : bool ,
418425}
419426
420427impl DecryptionPropertiesBuilder {
@@ -426,6 +433,7 @@ impl DecryptionPropertiesBuilder {
426433 key_retriever : None ,
427434 column_keys : HashMap :: default ( ) ,
428435 aad_prefix : None ,
436+ footer_signature_verification : true ,
429437 }
430438 }
431439
@@ -439,6 +447,7 @@ impl DecryptionPropertiesBuilder {
439447 key_retriever : Some ( key_retriever) ,
440448 column_keys : HashMap :: default ( ) ,
441449 aad_prefix : None ,
450+ footer_signature_verification : true ,
442451 }
443452 }
444453
@@ -464,6 +473,7 @@ impl DecryptionPropertiesBuilder {
464473 Ok ( FileDecryptionProperties {
465474 keys,
466475 aad_prefix : self . aad_prefix ,
476+ footer_signature_verification : self . footer_signature_verification ,
467477 } )
468478 }
469479
@@ -496,6 +506,13 @@ impl DecryptionPropertiesBuilder {
496506 }
497507 Ok ( self )
498508 }
509+
510+ /// Disable verification of footer tags for files that use plaintext footers.
511+ /// Signature verification is enabled by default.
512+ pub fn disable_footer_signature_verification ( mut self ) -> Self {
513+ self . footer_signature_verification = false ;
514+ self
515+ }
499516}
500517
501518#[ derive( Clone , Debug ) ]
@@ -538,6 +555,25 @@ impl FileDecryptor {
538555 Ok ( self . footer_decryptor . clone ( ) )
539556 }
540557
558+ /// Verify the signature of the footer
559+ pub ( crate ) fn verify_plaintext_footer_signature ( & self , plaintext_footer : & [ u8 ] ) -> Result < ( ) > {
560+ // Plaintext footer format is: [plaintext metadata, nonce, authentication tag]
561+ let tag = & plaintext_footer[ plaintext_footer. len ( ) - TAG_LEN ..] ;
562+ let aad = create_footer_aad ( self . file_aad ( ) ) ?;
563+ let footer_decryptor = self . get_footer_decryptor ( ) ?;
564+
565+ let computed_tag = footer_decryptor. compute_plaintext_tag ( & aad, plaintext_footer) ?;
566+
567+ if computed_tag != tag {
568+ return Err ( general_err ! (
569+ "Footer signature verification failed. Computed: {:?}, Expected: {:?}" ,
570+ computed_tag,
571+ tag
572+ ) ) ;
573+ }
574+ Ok ( ( ) )
575+ }
576+
541577 pub ( crate ) fn get_column_data_decryptor (
542578 & self ,
543579 column_name : & str ,
0 commit comments