This is an automated email from the ASF dual-hosted git repository.

gershinsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/parquet-mr.git


The following commit(s) were added to refs/heads/master by this push:
     new efb7554fa complete column encr (#1178)
efb7554fa is described below

commit efb7554faa1e1d7649916fa175430e21a266153e
Author: ggershinsky <[email protected]>
AuthorDate: Thu Oct 26 14:40:14 2023 +0300

    complete column encr (#1178)
---
 .../parquet/crypto/FileEncryptionProperties.java   | 37 +++++++++++++++++----
 .../parquet/hadoop/TestEncryptionOptions.java      | 38 +++++++++++++++++++---
 2 files changed, 63 insertions(+), 12 deletions(-)

diff --git 
a/parquet-hadoop/src/main/java/org/apache/parquet/crypto/FileEncryptionProperties.java
 
b/parquet-hadoop/src/main/java/org/apache/parquet/crypto/FileEncryptionProperties.java
index 96a570a77..208d53e7a 100755
--- 
a/parquet-hadoop/src/main/java/org/apache/parquet/crypto/FileEncryptionProperties.java
+++ 
b/parquet-hadoop/src/main/java/org/apache/parquet/crypto/FileEncryptionProperties.java
@@ -33,6 +33,7 @@ public class FileEncryptionProperties {
 
   private static final ParquetCipher ALGORITHM_DEFAULT = 
ParquetCipher.AES_GCM_V1;
   private static final boolean ENCRYPTED_FOOTER_DEFAULT = true;
+  private static final boolean COMPLETE_COLUMN_ENCRYPTION_DEFAULT = false;
 
   private final EncryptionAlgorithm algorithm;
   private final boolean encryptedFooter;
@@ -40,11 +41,13 @@ public class FileEncryptionProperties {
   private final byte[] footerKeyMetadata;
   private final byte[] fileAAD;
   private final Map<ColumnPath, ColumnEncryptionProperties> columnPropertyMap;
+  private final boolean completeColumnEncryption;
 
   private FileEncryptionProperties(ParquetCipher cipher, 
       byte[] footerKey, byte[] footerKeyMetadata, boolean encryptedFooter,
       byte[] aadPrefix, boolean storeAadPrefixInFile,
-      Map<ColumnPath, ColumnEncryptionProperties> columnPropertyMap) {
+      Map<ColumnPath, ColumnEncryptionProperties> columnPropertyMap,
+      boolean completeColumnEncryption) {
 
     if (null == footerKey) {
       throw new IllegalArgumentException("Footer key is null");
@@ -52,8 +55,14 @@ public class FileEncryptionProperties {
     if (! (footerKey.length == 16 || footerKey.length == 24 || 
footerKey.length == 32)) {
       throw new IllegalArgumentException("Wrong footer key length " + 
footerKey.length);
     }
-    if (null != columnPropertyMap && columnPropertyMap.size() == 0) {
-      throw new IllegalArgumentException("No encrypted columns");
+    if (null != columnPropertyMap) {
+      if (columnPropertyMap.size() == 0) {
+        throw new IllegalArgumentException("No encrypted columns");
+      }
+    } else {
+      if (completeColumnEncryption) {
+        throw new IllegalArgumentException("Encrypted columns are not 
specified, cannot complete");
+      }
     }
 
     SecureRandom random = new SecureRandom();
@@ -88,6 +97,7 @@ public class FileEncryptionProperties {
     this.footerKeyMetadata = footerKeyMetadata;
     this.encryptedFooter = encryptedFooter;
     this.columnPropertyMap = columnPropertyMap;
+    this.completeColumnEncryption = completeColumnEncryption;
   }
 
   /**
@@ -109,10 +119,12 @@ public class FileEncryptionProperties {
     private byte[] aadPrefix;
     private Map<ColumnPath, ColumnEncryptionProperties> columnPropertyMap;
     private boolean storeAadPrefixInFile;
+    private boolean completeColumnEncryption;
 
     private Builder(byte[] footerKey) {
       this.parquetCipher = ALGORITHM_DEFAULT;
       this.encryptedFooter = ENCRYPTED_FOOTER_DEFAULT;
+      this.completeColumnEncryption = COMPLETE_COLUMN_ENCRYPTION_DEFAULT;
       this.footerKeyBytes = new byte[footerKey.length];
       System.arraycopy(footerKey, 0, this.footerKeyBytes, 0, footerKey.length);
     }
@@ -229,11 +241,17 @@ public class FileEncryptionProperties {
       return this;
     }
 
+    public Builder withCompleteColumnEncryption() {
+      this.completeColumnEncryption = true;
+
+      return this;
+    }
+
     public FileEncryptionProperties build() {
       return new FileEncryptionProperties(parquetCipher, 
           footerKeyBytes, footerKeyMetadata, encryptedFooter,
           aadPrefix, storeAadPrefixInFile, 
-          columnPropertyMap);
+          columnPropertyMap, completeColumnEncryption);
     }
   }
 
@@ -261,9 +279,14 @@ public class FileEncryptionProperties {
       ColumnEncryptionProperties columnProperties = 
columnPropertyMap.get(columnPath);
       if (null != columnProperties) {
         return columnProperties;
-      } else {
-        // plaintext column
-        return ColumnEncryptionProperties.builder(columnPath, false).build();
+      } else { // not set explicitly
+        if (completeColumnEncryption) {
+          // encrypted with footer key
+          return ColumnEncryptionProperties.builder(columnPath, true).build();
+        } else {
+          // plaintext column
+          return ColumnEncryptionProperties.builder(columnPath, false).build();
+       }
       }
     }
   }
diff --git 
a/parquet-hadoop/src/test/java/org/apache/parquet/hadoop/TestEncryptionOptions.java
 
b/parquet-hadoop/src/test/java/org/apache/parquet/hadoop/TestEncryptionOptions.java
index a212c091f..e3ddb3e4c 100644
--- 
a/parquet-hadoop/src/test/java/org/apache/parquet/hadoop/TestEncryptionOptions.java
+++ 
b/parquet-hadoop/src/test/java/org/apache/parquet/hadoop/TestEncryptionOptions.java
@@ -20,7 +20,6 @@ package org.apache.parquet.hadoop;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.FSDataOutputStream;
 import org.apache.parquet.crypto.ColumnDecryptionProperties;
@@ -45,11 +44,8 @@ import org.junit.rules.ErrorCollector;
 import org.junit.rules.TemporaryFolder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import okhttp3.ConnectionSpec;
-import okhttp3.MediaType;
 import okhttp3.OkHttpClient;
 import okhttp3.Request;
-import okhttp3.RequestBody;
 import okhttp3.Response;
 
 import java.io.IOException;
@@ -100,6 +96,9 @@ import static 
org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT32;
  *  ENCRYPT_COLUMNS_PLAINTEXT_FOOTER: Encrypt six columns, with different keys.
  *                                  Do not encrypt footer (to enable legacy 
readers)
  *                                  - plaintext footer mode.
+ *  ENCRYPT_COLUMNS_PLAINTEXT_FOOTER_COMPLETE: Encrypt six columns with 
different keys
+ *                                  Do not encrypt footer. Encrypt the rest of 
the columns
+ *                                  with the footer key.
  *  ENCRYPT_COLUMNS_AND_FOOTER_AAD: Encrypt six columns and the footer, with 
different
  *                                  keys. Supply aad_prefix for file identity
  *                                  verification.
@@ -255,6 +254,21 @@ public class TestEncryptionOptions {
           .withFooterKeyMetadata(footerKeyMetadata).build();
       }
     },
+    ENCRYPT_COLUMNS_PLAIN_FOOTER_COMPLETE {
+      /**
+       * Encryption configuration 8: Encrypt six columns with different keys.
+       * Encrypt the rest of the columns with the footer key. Don't encrypt 
footer.
+       */
+      public FileEncryptionProperties getEncryptionProperties() {
+        Map<ColumnPath, ColumnEncryptionProperties> columnPropertiesMap = 
getColumnEncryptionPropertiesMap();
+        return FileEncryptionProperties.builder(FOOTER_ENCRYPTION_KEY)
+          .withFooterKeyMetadata(footerKeyMetadata)
+          .withEncryptedColumns(columnPropertiesMap)
+          .withCompleteColumnEncryption()
+          .withPlaintextFooter()
+          .build();
+      }
+    },
     NO_ENCRYPTION {
       public FileEncryptionProperties getEncryptionProperties() {
         return null;
@@ -402,6 +416,14 @@ public class TestEncryptionOptions {
             .named("FormatTestObject").toString());
         }
 
+        // Project column encrypted with footer key
+        if ((decryptionConfiguration == DecryptionConfiguration.NO_DECRYPTION) 
&&
+          (encryptionConfiguration == 
EncryptionConfiguration.ENCRYPT_COLUMNS_PLAIN_FOOTER_COMPLETE)) {
+          conf.set("parquet.read.schema", Types.buildMessage()
+            .optional(INT32).named(SingleRow.PLAINTEXT_INT32_FIELD_NAME)
+            .named("FormatTestObject").toString());
+        }
+
         int rowNum = 0;
         try (ParquetReader<Group> reader = ParquetReader.builder(new 
GroupReadSupport(), file)
           .withConf(conf)
@@ -471,6 +493,9 @@ public class TestEncryptionOptions {
       if (EncryptionConfiguration.UNIFORM_ENCRYPTION_PLAINTEXT_FOOTER == 
encryptionConfiguration) {
         continue;
       }
+      if (EncryptionConfiguration.ENCRYPT_COLUMNS_PLAIN_FOOTER_COMPLETE == 
encryptionConfiguration) {
+        continue;
+      }
       String fileName = getFileName(encryptionConfiguration);
       Path file = new Path(rootPath, fileName);
       if (!fs.exists(file)) {
@@ -500,6 +525,9 @@ public class TestEncryptionOptions {
         if (EncryptionConfiguration.UNIFORM_ENCRYPTION_PLAINTEXT_FOOTER == 
encryptionConfiguration) {
           continue;
         }
+        if (EncryptionConfiguration.ENCRYPT_COLUMNS_PLAIN_FOOTER_COMPLETE == 
encryptionConfiguration) {
+          continue;
+        }
         Path file = new Path(root, getFileName(encryptionConfiguration));
         LOG.info("==> Decryption configuration {}", decryptionConfiguration);
         FileDecryptionProperties fileDecryptionProperties = 
decryptionConfiguration.getDecryptionProperties();
@@ -593,7 +621,7 @@ public class TestEncryptionOptions {
         return;
       }
     }
-    // Encryption_configuration 7 has null encryptor, so parquet is plaintext.
+    // Last encryption_configuration has null encryptor, so parquet is 
plaintext.
     // An exception is expected to be thrown if the file is being decrypted.
     if (encryptionConfiguration == EncryptionConfiguration.NO_ENCRYPTION) {
       if ((decryptionConfiguration == 
DecryptionConfiguration.DECRYPT_WITH_KEY_RETRIEVER) ||

Reply via email to