jt2594838 commented on code in PR #213:
URL: https://github.com/apache/tsfile/pull/213#discussion_r1732208881


##########
java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java:
##########
@@ -215,6 +228,58 @@ public TSFileConfig() {
     // do nothing because we already give default value to each field when 
they are being declared
   }
 
+  public boolean getEncryptFlag() {
+    return Objects.equals(this.encryptFlag, "true");
+  }
+
+  public void setEncryptFlag(String encryptFlag) {
+    this.encryptFlag = encryptFlag;
+  }
+
+  public String getEncryptType() {
+    return this.encryptType;
+  }
+
+  public void setEncryptType(String encryptType) {
+    this.encryptType = encryptType;
+  }
+
+  public String getEncryptKey() {
+    return this.encryptKey;
+  }
+
+  public void setEncryptKey(String encryptKey) {
+    this.encryptKey = encryptKey;
+  }
+
+  public void setEncryptKeyFromPath(String encryptKeyPath) {
+    if (!encryptFlag.equals("true")) {
+      return;
+    }
+    if (encryptKeyPath == null) {
+      throw new RuntimeException("encrypt key path is null");
+    }
+    if (encryptKeyPath.isEmpty()) {
+      throw new RuntimeException("encrypt key path is empty");
+    }
+    try (BufferedReader br = new BufferedReader(new 
FileReader(encryptKeyPath))) {
+      StringBuilder sb = new StringBuilder();
+      String line;
+      boolean first = true;
+      while ((line = br.readLine()) != null) {
+        if (first) {
+          sb.append(line);
+          first = false;
+        } else {
+          sb.append("\n").append(line);
+        }
+      }
+      this.encryptKey = sb.toString();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }

Review Comment:
   Exception handle is not normally done in TsFileConfig, and you should do it 
in "TSFileDescriptor" or in the method caller. It would be better to leave the 
setter as simple as others.



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/IDecryptor.java:
##########
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/** encrypt data according to tsfileconfig. */
+public interface IDecryptor extends Serializable {

Review Comment:
   Why should a Decryptor be Serializable? The same for the Encryptor.



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/IDecryptor.java:
##########
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/** encrypt data according to tsfileconfig. */
+public interface IDecryptor extends Serializable {
+
+  static IDecryptor getDecryptor(String name, byte[] key) {
+    return getDecryptor(EncryptionType.valueOf(name), key);
+  }
+
+  static IDecryptor getDecryptor(EncryptionType name, byte[] key) {
+    if (name == null) {
+      return new NoDecryptor();
+    }
+    switch (name) {
+      case UNENCRYPTED:
+        return new NoDecryptor();
+      case SM4128:
+        return new SM4128Decryptor(key);
+      case AES128:
+        return new AES128Decryptor(key);
+      default:
+        return new NoDecryptor();

Review Comment:
   Add a warning log here.



##########
java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TsFileMetadata.java:
##########
@@ -105,12 +113,89 @@ public static TsFileMetadata deserializeFrom(ByteBuffer 
buffer, DeserializeConfi
         String value = ReadWriteIOUtils.readVarIntString(buffer);
         propertiesMap.put(key, value);
       }
+      // if the file is not encrypted, set the default value(for compatible 
reason)
+      if (!propertiesMap.containsKey("encryptLevel")) {
+        propertiesMap.put("encryptLevel", "0");
+        propertiesMap.put("encryptType", "UNENCRYPTED");
+        propertiesMap.put("encryptKey", "");
+      } else if (propertiesMap.get("encryptLevel") == null) {
+        propertiesMap.put("encryptLevel", "0");
+        propertiesMap.put("encryptType", "UNENCRYPTED");
+        propertiesMap.put("encryptKey", "");

Review Comment:
   What is the difference of the two branches?



##########
java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java:
##########
@@ -355,6 +359,39 @@ public BloomFilter readBloomFilter() throws IOException {
     return tsFileMetaData.getBloomFilter();
   }
 
+  /**
+   * Retrieves the decryptor for the TsFile. This method reads the file 
metadata to obtain the
+   * decryptor information. If an error occurs while reading the metadata, it 
logs the error and
+   * attempts to retrieve the decryptor based on the configuration settings.
+   *
+   * @return the decryptor for the TsFile
+   * @throws IOException if an I/O error occurs while reading the file metadata
+   */
+  public IDecryptor getDecryptor() throws IOException {
+    try {
+      readFileMetadata();
+    } catch (Exception e) {
+      String encryptType;
+      byte[] dataEncryptKey;
+      if (config.getEncryptFlag()) {
+        encryptType = config.getEncryptType();
+        try {
+          MessageDigest md = MessageDigest.getInstance("MD5");
+          md.update("IoTDB is the best".getBytes());
+          md.update(config.getEncryptKey().getBytes());
+          dataEncryptKey = md.digest();
+        } catch (Exception e1) {
+          throw new EncryptException("md5 function not found while use md5 to 
generate data key");

Review Comment:
   use -> using



##########
java/tsfile/src/main/java/org/apache/tsfile/read/reader/chunk/ChunkReader.java:
##########
@@ -163,17 +167,32 @@ public static ByteBuffer 
readCompressedPageData(PageHeader pageHeader, ByteBuffe
   }
 
   public static ByteBuffer uncompressPageData(
-      PageHeader pageHeader, IUnCompressor unCompressor, ByteBuffer 
compressedPageData)
+      PageHeader pageHeader,
+      IUnCompressor unCompressor,
+      ByteBuffer compressedPageData,
+      IDecryptor decryptor)
       throws IOException {
     int compressedPageBodyLength = pageHeader.getCompressedSize();
     byte[] uncompressedPageData = new byte[pageHeader.getUncompressedSize()];
+    byte[] decryptedPageData = new byte[pageHeader.getCompressedSize()];
     try {
+      //      unCompressor.uncompress(
+      //          compressedPageData.array(),
+      //          compressedPageData.arrayOffset() + 
compressedPageData.position(),
+      //          compressedPageBodyLength,
+      //          uncompressedPageData,
+      //          0);
+      System.arraycopy(
+          decryptor.decrypt(
+              compressedPageData.array(),
+              compressedPageData.arrayOffset() + compressedPageData.position(),
+              compressedPageBodyLength),
+          0,
+          decryptedPageData,
+          0,
+          compressedPageBodyLength);

Review Comment:
   Why use copying instead of assigning?



##########
java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java:
##########
@@ -215,6 +228,58 @@ public TSFileConfig() {
     // do nothing because we already give default value to each field when 
they are being declared
   }
 
+  public boolean getEncryptFlag() {
+    return Objects.equals(this.encryptFlag, "true");
+  }
+
+  public void setEncryptFlag(String encryptFlag) {
+    this.encryptFlag = encryptFlag;
+  }

Review Comment:
   Why not just declare "encryptFlag" as a boolean?



##########
java/tsfile/src/main/java/org/apache/tsfile/write/writer/TsFileIOWriter.java:
##########
@@ -139,6 +148,72 @@ public TsFileIOWriter(File file) throws IOException {
     if (resourceLogger.isDebugEnabled()) {
       resourceLogger.debug("{} writer is opened.", file.getName());
     }
+    if (TS_FILE_CONFIG.getEncryptFlag()) {
+      this.encryptLevel = "2";
+      this.encryptType = TS_FILE_CONFIG.getEncryptType();
+      try {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update("IoTDB is the best".getBytes());
+        md.update(TS_FILE_CONFIG.getEncryptKey().getBytes());
+        byte[] tem = md.digest();
+        byte[] tem1 =
+            IEncryptor.getEncryptor(
+                    TS_FILE_CONFIG.getEncryptType(), 
TS_FILE_CONFIG.getEncryptKey().getBytes())
+                .encrypt(tem);
+        StringBuilder valueStr = new StringBuilder();
+
+        for (byte b : tem1) {
+          valueStr.append(b).append(",");
+        }
+
+        valueStr.deleteCharAt(valueStr.length() - 1);
+        String str = valueStr.toString();
+
+        this.encryptKey = str;
+      } catch (Exception e) {
+        throw new EncryptException("md5 function not found while use md5 to 
generate data key");
+      }
+    } else {
+      this.encryptLevel = "0";
+      this.encryptType = "UNENCRYPTED";
+      this.encryptKey = null;
+    }
+    startFile();
+  }
+
+  /** for test only */
+  public TsFileIOWriter(File file, TSFileConfig conf) throws IOException {
+    this.out = 
FSFactoryProducer.getFileOutputFactory().getTsFileOutput(file.getPath(), false);
+    this.file = file;
+    if (resourceLogger.isDebugEnabled()) {
+      resourceLogger.debug("{} writer is opened.", file.getName());
+    }
+    if (conf.getEncryptFlag()) {
+      this.encryptLevel = "2";
+      this.encryptType = conf.getEncryptType();
+      try {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update("IoTDB is the best".getBytes());
+        md.update(conf.getEncryptKey().getBytes());
+        byte[] data_key = md.digest();
+        StringBuilder valueStr = new StringBuilder();
+        // 给每个byte之间加上,进行分割
+        for (byte b : data_key) {
+          valueStr.append(b).append(",");
+        }
+        // 最后的逗号去掉
+        valueStr.deleteCharAt(valueStr.length() - 1);
+        String str = valueStr.toString();

Review Comment:
   Use English.



##########
java/tsfile/src/test/java/org/apache/tsfile/encrypt/EncryptTest.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+import org.apache.tsfile.utils.PublicBAOS;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.assertEquals;
+
+public class EncryptTest {
+  private final String inputString =
+      "Hello snappy-java! Snappy-java is a JNI-based wrapper of "
+          + "AES, a fast encryptor/decryptor.";

Review Comment:
   What?



##########
java/tsfile/src/test/java/org/apache/tsfile/encrypt/AES128TsFileWriteTest.java:
##########
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.common.conf.TSFileDescriptor;
+import org.apache.tsfile.common.constant.JsonFormatConstant;
+import org.apache.tsfile.constant.TestConstant;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.exception.write.WriteProcessException;
+import org.apache.tsfile.file.metadata.TsFileMetadata;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.read.TsFileSequenceReader;
+import org.apache.tsfile.read.common.Path;
+import org.apache.tsfile.utils.RecordUtils;
+import org.apache.tsfile.utils.StringContainer;
+import org.apache.tsfile.write.TsFileWriter;
+import org.apache.tsfile.write.WriteTest;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.schema.IMeasurementSchema;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.apache.tsfile.write.schema.Schema;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class AES128TsFileWriteTest {
+  private static final Logger LOG = LoggerFactory.getLogger(WriteTest.class);
+  private final int ROW_COUNT = 2000000;
+  private TsFileWriter tsFileWriter;
+  private String inputDataFile;
+  private String outputDataFile;
+  private String errorOutputDataFile;
+  private Random rm = new Random();
+  private ArrayList<IMeasurementSchema> measurementArray;
+  private ArrayList<Path> pathArray;
+  private Schema schema;
+  private int stageSize = 4;
+  private int stageState = -1;
+  private int prePageSize;
+  private int prePageCheckThres;
+  private TSFileConfig conf = TSFileDescriptor.getInstance().getConfig();
+
+  private String[][] stageDeviceIds = {{"d1", "d2", "d3"}, {"d1"}, {"d2", 
"d3"}};
+  private String[] measurementIds = {"s0", "s1", "s2", "s3", "s4", "s5"};
+  private long longBase = System.currentTimeMillis() * 1000;
+  private String[] enums = {"MAN", "WOMAN"};
+
+  @Before
+  public void prepare() throws IOException {
+    inputDataFile = TestConstant.BASE_OUTPUT_PATH.concat("writeTestInputData");
+    outputDataFile = 
TestConstant.BASE_OUTPUT_PATH.concat("writeTestOutputData.tsfile");
+    errorOutputDataFile = 
TestConstant.BASE_OUTPUT_PATH.concat("writeTestErrorOutputData.tsfile");
+    // for each row, flush page forcely
+    prePageSize = conf.getPageSizeInByte();
+    conf.setPageSizeInByte(0);
+    prePageCheckThres = conf.getPageCheckSizeThreshold();
+    conf.setPageCheckSizeThreshold(0);
+    conf.setEncryptFlag("true");
+    conf.setEncryptType("AES128");
+    conf.setEncryptKey("thisisourtestkey");
+
+    try {
+      generateSampleInputDataFile();
+    } catch (IOException e) {
+      fail();

Review Comment:
   Throw the exception or provide its message in fail().



##########
java/tsfile/src/main/java/org/apache/tsfile/write/TsFileWriter.java:
##########
@@ -69,6 +72,16 @@ public class TsFileWriter implements AutoCloseable {
   /** IO writer of this TsFile. */
   private final TsFileIOWriter fileWriter;
 
+  private String encryptLevel;
+
+  private String encryptType;
+
+  private byte[] encryptKey;
+
+  private byte[] dataEncryptKey;

Review Comment:
   Are these fields necessary to be class members? They do not seem to be used 
outside of the constructor.



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/IEncryptor.java:
##########
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/** encrypt data according to tsfileconfig. */
+public interface IEncryptor extends Serializable {
+
+  static IEncryptor getEncryptor(String name, byte[] key) {
+    return getEncryptor(EncryptionType.valueOf(name), key);
+  }
+
+  static IEncryptor getEncryptor(EncryptionType name, byte[] key) {
+    if (name == null) {
+      return new NoEncryptor();
+    }
+    switch (name) {
+      case SM4128:
+        return new SM4128Encryptor(key);
+      case AES128:
+        return new AES128Encryptor(key);
+      default:
+        return new NoEncryptor();
+    }
+  }
+
+  byte[] encrypt(byte[] data);
+
+  byte[] encrypt(byte[] data, int offset, int size);
+
+  EncryptionType getEncryptionType();
+
+  class NoEncryptor implements IEncryptor {
+
+    @Override
+    public byte[] encrypt(byte[] data) {
+      return data;
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data, int offset, int size) {
+      return Arrays.copyOfRange(data, offset, offset + size);
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.UNENCRYPTED;
+    }
+  }
+
+  class SM4128Encryptor implements IEncryptor {
+
+    private final SM4Utils sm4;
+
+    SM4128Encryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      this.sm4 = new SM4Utils(key, key);
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data) {
+      return sm4.cryptData_CTR(Arrays.copyOf(data, data.length));
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data, int offset, int size) {
+      return encrypt(Arrays.copyOfRange(data, offset, offset + size));
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.SM4128;
+    }
+  }
+
+  class AES128Encryptor implements IEncryptor {
+    private final Cipher AES;
+
+    AES128Encryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
+      // Create IV parameter
+      IvParameterSpec ivParameterSpec = new IvParameterSpec(key);
+      try {
+        // Create Cipher instance and initialize it for encryption in CTR mode 
without padding
+        this.AES = Cipher.getInstance("AES/CTR/NoPadding");
+        AES.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
+      } catch (InvalidAlgorithmParameterException
+          | NoSuchPaddingException
+          | NoSuchAlgorithmException
+          | InvalidKeyException e) {
+        throw new EncryptException("AES128Encryptor init failed");
+      }
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data) {
+      try {
+        return AES.doFinal(data);
+      } catch (IllegalBlockSizeException | BadPaddingException e) {
+        throw new EncryptException("AES128Encryptor encrypt failed");
+      }
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data, int offset, int size) {
+      return encrypt(Arrays.copyOfRange(data, offset, offset + size));

Review Comment:
   The Cipher provides an interface that can read partially from a byte[], so 
you do not need to copy one.
   Check if SM4 has the same interface and modify the decryptor.
   
![image](https://github.com/user-attachments/assets/a36a5bf5-1c1b-4b6a-9fb0-936e3d8fe549)
   



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/IEncryptor.java:
##########
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/** encrypt data according to tsfileconfig. */
+public interface IEncryptor extends Serializable {
+
+  static IEncryptor getEncryptor(String name, byte[] key) {
+    return getEncryptor(EncryptionType.valueOf(name), key);
+  }
+
+  static IEncryptor getEncryptor(EncryptionType name, byte[] key) {
+    if (name == null) {
+      return new NoEncryptor();
+    }
+    switch (name) {
+      case SM4128:
+        return new SM4128Encryptor(key);
+      case AES128:
+        return new AES128Encryptor(key);
+      default:
+        return new NoEncryptor();
+    }
+  }
+
+  byte[] encrypt(byte[] data);
+
+  byte[] encrypt(byte[] data, int offset, int size);
+
+  EncryptionType getEncryptionType();
+
+  class NoEncryptor implements IEncryptor {
+
+    @Override
+    public byte[] encrypt(byte[] data) {
+      return data;
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data, int offset, int size) {
+      return Arrays.copyOfRange(data, offset, offset + size);
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.UNENCRYPTED;
+    }
+  }
+
+  class SM4128Encryptor implements IEncryptor {
+
+    private final SM4Utils sm4;
+
+    SM4128Encryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      this.sm4 = new SM4Utils(key, key);
+    }
+
+    @Override
+    public byte[] encrypt(byte[] data) {
+      return sm4.cryptData_CTR(Arrays.copyOf(data, data.length));

Review Comment:
   Why is a copy needed here?



##########
java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java:
##########
@@ -136,6 +140,15 @@ public class TSFileConfig implements Serializable {
   /** Data compression method, TsFile supports UNCOMPRESSED, SNAPPY, ZSTD or 
LZ4. */
   private CompressionType compressor = CompressionType.LZ4;
 
+  /** encryptFlag, this should be false by default */
+  private String encryptFlag = "false";
+
+  /** encryptKey, this should be null by default */
+  private String encryptKey = "abcdefghijklmnop";
+
+  /** encryptType, this should be null by defalut */
+  private String encryptType = "UNENCRYPTED";
+

Review Comment:
   “This should be null by default”?
   Also, add to the comments what the supported encryption types are; it would 
be better to use an enum class.
   And, now that one type of encryption is "UNENCRYPTED", is it necessary to 
have the encryptFlag?



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/IDecryptor.java:
##########
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/** encrypt data according to tsfileconfig. */
+public interface IDecryptor extends Serializable {
+
+  static IDecryptor getDecryptor(String name, byte[] key) {
+    return getDecryptor(EncryptionType.valueOf(name), key);
+  }
+
+  static IDecryptor getDecryptor(EncryptionType name, byte[] key) {
+    if (name == null) {
+      return new NoDecryptor();
+    }
+    switch (name) {
+      case UNENCRYPTED:
+        return new NoDecryptor();
+      case SM4128:
+        return new SM4128Decryptor(key);
+      case AES128:
+        return new AES128Decryptor(key);
+      default:
+        return new NoDecryptor();
+    }
+  }
+
+  byte[] decrypt(byte[] data);
+
+  byte[] decrypt(byte[] data, int offset, int size);
+
+  EncryptionType getEncryptionType();
+
+  class NoDecryptor implements IDecryptor {
+
+    @Override
+    public byte[] decrypt(byte[] data) {
+      return data;
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data, int offset, int size) {
+      return Arrays.copyOfRange(data, offset, offset + size);
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.UNENCRYPTED;
+    }
+  }
+
+  class SM4128Decryptor implements IDecryptor {
+
+    private final SM4Utils sm4;
+
+    SM4128Decryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      this.sm4 = new SM4Utils(key, key);
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data) {
+      return sm4.cryptData_CTR(data);
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data, int offset, int size) {
+      return decrypt(Arrays.copyOfRange(data, offset, offset + size));
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.SM4128;
+    }
+  }
+
+  class AES128Decryptor implements IDecryptor {
+    private final Cipher AES;
+
+    AES128Decryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
+      // Create IV parameter
+      IvParameterSpec ivParameterSpec = new IvParameterSpec(key);
+      try {
+        // Create Cipher instance and initialize it for encryption in CTR mode 
without padding
+        this.AES = Cipher.getInstance("AES/CTR/NoPadding");
+        AES.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
+      } catch (InvalidAlgorithmParameterException
+          | NoSuchPaddingException
+          | NoSuchAlgorithmException
+          | InvalidKeyException e) {
+        throw new EncryptException("AES128Decryptor init failed");

Review Comment:
   Include `e` as the cause to provide more specific information.



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/IDecryptor.java:
##########
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+import org.apache.tsfile.file.metadata.enums.EncryptionType;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.io.Serializable;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/** encrypt data according to tsfileconfig. */
+public interface IDecryptor extends Serializable {
+
+  static IDecryptor getDecryptor(String name, byte[] key) {
+    return getDecryptor(EncryptionType.valueOf(name), key);
+  }
+
+  static IDecryptor getDecryptor(EncryptionType name, byte[] key) {
+    if (name == null) {
+      return new NoDecryptor();
+    }
+    switch (name) {
+      case UNENCRYPTED:
+        return new NoDecryptor();
+      case SM4128:
+        return new SM4128Decryptor(key);
+      case AES128:
+        return new AES128Decryptor(key);
+      default:
+        return new NoDecryptor();
+    }
+  }
+
+  byte[] decrypt(byte[] data);
+
+  byte[] decrypt(byte[] data, int offset, int size);
+
+  EncryptionType getEncryptionType();
+
+  class NoDecryptor implements IDecryptor {
+
+    @Override
+    public byte[] decrypt(byte[] data) {
+      return data;
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data, int offset, int size) {
+      return Arrays.copyOfRange(data, offset, offset + size);
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.UNENCRYPTED;
+    }
+  }
+
+  class SM4128Decryptor implements IDecryptor {
+
+    private final SM4Utils sm4;
+
+    SM4128Decryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      this.sm4 = new SM4Utils(key, key);
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data) {
+      return sm4.cryptData_CTR(data);
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data, int offset, int size) {
+      return decrypt(Arrays.copyOfRange(data, offset, offset + size));
+    }
+
+    @Override
+    public EncryptionType getEncryptionType() {
+      return EncryptionType.SM4128;
+    }
+  }
+
+  class AES128Decryptor implements IDecryptor {
+    private final Cipher AES;
+
+    AES128Decryptor(byte[] key) {
+      if (key.length != 16) {
+        throw new EncryptKeyLengthNotMatchException(16, key.length);
+      }
+      SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
+      // Create IV parameter
+      IvParameterSpec ivParameterSpec = new IvParameterSpec(key);
+      try {
+        // Create Cipher instance and initialize it for encryption in CTR mode 
without padding
+        this.AES = Cipher.getInstance("AES/CTR/NoPadding");
+        AES.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
+      } catch (InvalidAlgorithmParameterException
+          | NoSuchPaddingException
+          | NoSuchAlgorithmException
+          | InvalidKeyException e) {
+        throw new EncryptException("AES128Decryptor init failed");
+      }
+    }
+
+    @Override
+    public byte[] decrypt(byte[] data) {
+      try {
+        return AES.doFinal(data);
+      } catch (IllegalBlockSizeException | BadPaddingException e) {
+        throw new EncryptException("AES128Decryptor decrypt failed");

Review Comment:
   Include `e` as the cause to provide more specific information. Check other 
places.



##########
java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TsFileMetadata.java:
##########
@@ -105,12 +113,89 @@ public static TsFileMetadata deserializeFrom(ByteBuffer 
buffer, DeserializeConfi
         String value = ReadWriteIOUtils.readVarIntString(buffer);
         propertiesMap.put(key, value);
       }
+      // if the file is not encrypted, set the default value(for compatible 
reason)
+      if (!propertiesMap.containsKey("encryptLevel")) {
+        propertiesMap.put("encryptLevel", "0");

Review Comment:
   Too long, better to put the code below into a function.



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/SM4.java:
##########
@@ -0,0 +1,578 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class SM4 {
+  public static final int SM4_ENCRYPT = 1;
+
+  public static final int SM4_DECRYPT = 0;
+
+  private long GET_ULONG_BE(byte[] b, int i) {
+    long n =
+        (long) (b[i] & 0xff) << 24
+            | (long) ((b[i + 1] & 0xff) << 16)
+            | (long) ((b[i + 2] & 0xff) << 8)
+            | (long) (b[i + 3] & 0xff) & 0xffffffffL;
+    return n;
+  }
+
+  private void PUT_ULONG_BE(long n, byte[] b, int i) {
+    b[i] = (byte) (int) (0xFF & n >> 24);
+    b[i + 1] = (byte) (int) (0xFF & n >> 16);
+    b[i + 2] = (byte) (int) (0xFF & n >> 8);
+    b[i + 3] = (byte) (int) (0xFF & n);
+  }
+
+  private long SHL(long x, int n) {
+    return (x & 0xFFFFFFFF) << n;
+  }
+
+  private long ROTL(long x, int n) {
+    return SHL(x, n) | x >> (32 - n);
+  }
+
+  private void SWAP(long[] sk, int i) {
+    long t = sk[i];
+    sk[i] = sk[(31 - i)];
+    sk[(31 - i)] = t;
+  }
+
+  public static final byte[] SboxTable = {
+    (byte) 0xd6,
+    (byte) 0x90,
+    (byte) 0xe9,
+    (byte) 0xfe,
+    (byte) 0xcc,
+    (byte) 0xe1,
+    0x3d,
+    (byte) 0xb7,
+    0x16,
+    (byte) 0xb6,
+    0x14,
+    (byte) 0xc2,
+    0x28,
+    (byte) 0xfb,
+    0x2c,
+    0x05,
+    0x2b,
+    0x67,
+    (byte) 0x9a,
+    0x76,
+    0x2a,
+    (byte) 0xbe,
+    0x04,
+    (byte) 0xc3,
+    (byte) 0xaa,
+    0x44,
+    0x13,
+    0x26,
+    0x49,
+    (byte) 0x86,
+    0x06,
+    (byte) 0x99,
+    (byte) 0x9c,
+    0x42,
+    0x50,
+    (byte) 0xf4,
+    (byte) 0x91,
+    (byte) 0xef,
+    (byte) 0x98,
+    0x7a,
+    0x33,
+    0x54,
+    0x0b,
+    0x43,
+    (byte) 0xed,
+    (byte) 0xcf,
+    (byte) 0xac,
+    0x62,
+    (byte) 0xe4,
+    (byte) 0xb3,
+    0x1c,
+    (byte) 0xa9,
+    (byte) 0xc9,
+    0x08,
+    (byte) 0xe8,
+    (byte) 0x95,
+    (byte) 0x80,
+    (byte) 0xdf,
+    (byte) 0x94,
+    (byte) 0xfa,
+    0x75,
+    (byte) 0x8f,
+    0x3f,
+    (byte) 0xa6,
+    0x47,
+    0x07,
+    (byte) 0xa7,
+    (byte) 0xfc,
+    (byte) 0xf3,
+    0x73,
+    0x17,
+    (byte) 0xba,
+    (byte) 0x83,
+    0x59,
+    0x3c,
+    0x19,
+    (byte) 0xe6,
+    (byte) 0x85,
+    0x4f,
+    (byte) 0xa8,
+    0x68,
+    0x6b,
+    (byte) 0x81,
+    (byte) 0xb2,
+    0x71,
+    0x64,
+    (byte) 0xda,
+    (byte) 0x8b,
+    (byte) 0xf8,
+    (byte) 0xeb,
+    0x0f,
+    0x4b,
+    0x70,
+    0x56,
+    (byte) 0x9d,
+    0x35,
+    0x1e,
+    0x24,
+    0x0e,
+    0x5e,
+    0x63,
+    0x58,
+    (byte) 0xd1,
+    (byte) 0xa2,
+    0x25,
+    0x22,
+    0x7c,
+    0x3b,
+    0x01,
+    0x21,
+    0x78,
+    (byte) 0x87,
+    (byte) 0xd4,
+    0x00,
+    0x46,
+    0x57,
+    (byte) 0x9f,
+    (byte) 0xd3,
+    0x27,
+    0x52,
+    0x4c,
+    0x36,
+    0x02,
+    (byte) 0xe7,
+    (byte) 0xa0,
+    (byte) 0xc4,
+    (byte) 0xc8,
+    (byte) 0x9e,
+    (byte) 0xea,
+    (byte) 0xbf,
+    (byte) 0x8a,
+    (byte) 0xd2,
+    0x40,
+    (byte) 0xc7,
+    0x38,
+    (byte) 0xb5,
+    (byte) 0xa3,
+    (byte) 0xf7,
+    (byte) 0xf2,
+    (byte) 0xce,
+    (byte) 0xf9,
+    0x61,
+    0x15,
+    (byte) 0xa1,
+    (byte) 0xe0,
+    (byte) 0xae,
+    0x5d,
+    (byte) 0xa4,
+    (byte) 0x9b,
+    0x34,
+    0x1a,
+    0x55,
+    (byte) 0xad,
+    (byte) 0x93,
+    0x32,
+    0x30,
+    (byte) 0xf5,
+    (byte) 0x8c,
+    (byte) 0xb1,
+    (byte) 0xe3,
+    0x1d,
+    (byte) 0xf6,
+    (byte) 0xe2,
+    0x2e,
+    (byte) 0x82,
+    0x66,
+    (byte) 0xca,
+    0x60,
+    (byte) 0xc0,
+    0x29,
+    0x23,
+    (byte) 0xab,
+    0x0d,
+    0x53,
+    0x4e,
+    0x6f,
+    (byte) 0xd5,
+    (byte) 0xdb,
+    0x37,
+    0x45,
+    (byte) 0xde,
+    (byte) 0xfd,
+    (byte) 0x8e,
+    0x2f,
+    0x03,
+    (byte) 0xff,
+    0x6a,
+    0x72,
+    0x6d,
+    0x6c,
+    0x5b,
+    0x51,
+    (byte) 0x8d,
+    0x1b,
+    (byte) 0xaf,
+    (byte) 0x92,
+    (byte) 0xbb,
+    (byte) 0xdd,
+    (byte) 0xbc,
+    0x7f,
+    0x11,
+    (byte) 0xd9,
+    0x5c,
+    0x41,
+    0x1f,
+    0x10,
+    0x5a,
+    (byte) 0xd8,
+    0x0a,
+    (byte) 0xc1,
+    0x31,
+    (byte) 0x88,
+    (byte) 0xa5,
+    (byte) 0xcd,
+    0x7b,
+    (byte) 0xbd,
+    0x2d,
+    0x74,
+    (byte) 0xd0,
+    0x12,
+    (byte) 0xb8,
+    (byte) 0xe5,
+    (byte) 0xb4,
+    (byte) 0xb0,
+    (byte) 0x89,
+    0x69,
+    (byte) 0x97,
+    0x4a,
+    0x0c,
+    (byte) 0x96,
+    0x77,
+    0x7e,
+    0x65,
+    (byte) 0xb9,
+    (byte) 0xf1,
+    0x09,
+    (byte) 0xc5,
+    0x6e,
+    (byte) 0xc6,
+    (byte) 0x84,
+    0x18,
+    (byte) 0xf0,
+    0x7d,
+    (byte) 0xec,
+    0x3a,
+    (byte) 0xdc,
+    0x4d,
+    0x20,
+    0x79,
+    (byte) 0xee,
+    0x5f,
+    0x3e,
+    (byte) 0xd7,
+    (byte) 0xcb,
+    0x39,
+    0x48
+  };
+
+  public static final int[] FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 
0xb27022dc};
+
+  public static final int[] CK = {
+    0x00070e15,
+    0x1c232a31,
+    0x383f464d,
+    0x545b6269,
+    0x70777e85,
+    0x8c939aa1,
+    0xa8afb6bd,
+    0xc4cbd2d9,
+    0xe0e7eef5,
+    0xfc030a11,
+    0x181f262d,
+    0x343b4249,
+    0x50575e65,
+    0x6c737a81,
+    0x888f969d,
+    0xa4abb2b9,
+    0xc0c7ced5,
+    0xdce3eaf1,
+    0xf8ff060d,
+    0x141b2229,
+    0x30373e45,
+    0x4c535a61,
+    0x686f767d,
+    0x848b9299,
+    0xa0a7aeb5,
+    0xbcc3cad1,
+    0xd8dfe6ed,
+    0xf4fb0209,
+    0x10171e25,
+    0x2c333a41,
+    0x484f565d,
+    0x646b7279
+  };
+
+  private byte sm4Sbox(byte inch) {
+    int i = inch & 0xFF;
+    byte retVal = SboxTable[i];
+    return retVal;
+  }
+
+  private long sm4Lt(long ka) {
+    long bb = 0L;
+    long c = 0L;
+    byte[] a = new byte[4];
+    byte[] b = new byte[4];
+    PUT_ULONG_BE(ka, a, 0);
+    b[0] = sm4Sbox(a[0]);
+    b[1] = sm4Sbox(a[1]);
+    b[2] = sm4Sbox(a[2]);
+    b[3] = sm4Sbox(a[3]);
+    bb = GET_ULONG_BE(b, 0);
+    c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
+    return c;
+  }
+
+  private long sm4F(long x0, long x1, long x2, long x3, long rk) {
+    return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
+  }
+
+  private long sm4CalciRK(long ka) {
+    long bb = 0L;
+    long rk = 0L;
+    byte[] a = new byte[4];
+    byte[] b = new byte[4];

Review Comment:
   If these methods are called very often, these local variables can be stored 
as class members to reduce memory allocation.



##########
java/tsfile/src/main/java/org/apache/tsfile/exception/encrypt/EncryptKeyLengthNotMatchException.java:
##########
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.exception.encrypt;
+
+public class EncryptKeyLengthNotMatchException extends RuntimeException {
+  public EncryptKeyLengthNotMatchException(int needed_length, int 
offer_length) {

Review Comment:
   Mind the naming style.



##########
java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TsFileMetadata.java:
##########
@@ -105,12 +113,89 @@ public static TsFileMetadata deserializeFrom(ByteBuffer 
buffer, DeserializeConfi
         String value = ReadWriteIOUtils.readVarIntString(buffer);
         propertiesMap.put(key, value);
       }
+      // if the file is not encrypted, set the default value(for compatible 
reason)
+      if (!propertiesMap.containsKey("encryptLevel")) {
+        propertiesMap.put("encryptLevel", "0");
+        propertiesMap.put("encryptType", "UNENCRYPTED");
+        propertiesMap.put("encryptKey", "");
+      } else if (propertiesMap.get("encryptLevel") == null) {
+        propertiesMap.put("encryptLevel", "0");
+        propertiesMap.put("encryptType", "UNENCRYPTED");
+        propertiesMap.put("encryptKey", "");
+      } else if (propertiesMap.get("encryptLevel").equals("0")) {
+        propertiesMap.put("encryptType", "UNENCRYPTED");
+        propertiesMap.put("encryptKey", "");
+      } else if (propertiesMap.get("encryptLevel").equals("1")) {
+        if (!propertiesMap.containsKey("encryptType")) {
+          throw new EncryptException("TsfileMetadata lack of encryptType while 
encryptLevel is 2");
+        }
+        if (!propertiesMap.containsKey("encryptKey")) {
+          throw new EncryptException("TsfileMetadata lack of encryptKey while 
encryptLevel is 2");
+        }
+        if (propertiesMap.get("encryptKey") == null || 
propertiesMap.get("encryptKey").isEmpty()) {
+          throw new EncryptException("TsfileMetadata null encryptKey while 
encryptLevel is 2");
+        }

Review Comment:
   "encryptLevel is 2"?



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/SM4.java:
##########
@@ -0,0 +1,578 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class SM4 {
+  public static final int SM4_ENCRYPT = 1;
+
+  public static final int SM4_DECRYPT = 0;
+
+  private long GET_ULONG_BE(byte[] b, int i) {
+    long n =
+        (long) (b[i] & 0xff) << 24
+            | (long) ((b[i + 1] & 0xff) << 16)
+            | (long) ((b[i + 2] & 0xff) << 8)
+            | (long) (b[i + 3] & 0xff) & 0xffffffffL;
+    return n;
+  }
+
+  private void PUT_ULONG_BE(long n, byte[] b, int i) {
+    b[i] = (byte) (int) (0xFF & n >> 24);
+    b[i + 1] = (byte) (int) (0xFF & n >> 16);
+    b[i + 2] = (byte) (int) (0xFF & n >> 8);
+    b[i + 3] = (byte) (int) (0xFF & n);
+  }
+
+  private long SHL(long x, int n) {
+    return (x & 0xFFFFFFFF) << n;
+  }
+
+  private long ROTL(long x, int n) {
+    return SHL(x, n) | x >> (32 - n);
+  }
+
+  private void SWAP(long[] sk, int i) {
+    long t = sk[i];
+    sk[i] = sk[(31 - i)];
+    sk[(31 - i)] = t;
+  }
+
+  public static final byte[] SboxTable = {
+    (byte) 0xd6,
+    (byte) 0x90,
+    (byte) 0xe9,
+    (byte) 0xfe,
+    (byte) 0xcc,
+    (byte) 0xe1,
+    0x3d,

Review Comment:
   This is, well, not so pretty if I may say that. How about writing a hex 
string and converting it into byte[]?
   The reference of converting a hex string to bytes can be found at:
   
https://www.baidu.com/s?wd=java%2016%E8%BF%9B%E5%88%B6%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%ACbyte%E6%95%B0%E7%BB%84&rsv_spt=1&rsv_iqid=0xf8dd9106001411a7&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_dl=tb&rsv_enter=1&rsv_sug3=52&rsv_sug1=2&rsv_sug7=100&rsv_t=fd7drmbhKY3JPtf63FyPUXhQTgdPniE4jK4PtQRlAmaGwLjuW%2FXqJxZ0t2yzJSEqTcxm&rsv_sug2=0&rsv_btype=i&prefixsug=java%252016%25E8%25BF%259B%25E5%2588%25B6%25E5%25AD%2597%25E7%25AC%25A6%25E4%25B8%25B2%25E8%25BD%25ACbyte%25E6%2595%25B0%25E7%25BB%2584&rsp=7&inputT=13076&rsv_sug4=13077&rsv_sug=1



##########
java/tsfile/src/main/java/org/apache/tsfile/file/metadata/enums/EncryptionType.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.file.metadata.enums;
+
+public enum EncryptionType {
+  /** Do not comprocess. */
+  UNENCRYPTED("", (byte) 0),
+
+  /** SNAPPY. */
+  SM4128("SM4128", (byte) 1),
+
+  /** GZIP. */
+  AES128("AES128", (byte) 2);

Review Comment:
   Mind the comments after copying.



##########
java/tsfile/src/main/java/org/apache/tsfile/file/metadata/enums/EncryptionType.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.file.metadata.enums;
+
+public enum EncryptionType {
+  /** Do not comprocess. */
+  UNENCRYPTED("", (byte) 0),
+
+  /** SNAPPY. */
+  SM4128("SM4128", (byte) 1),
+
+  /** GZIP. */
+  AES128("AES128", (byte) 2);
+
+  private final String extensionName;
+  private final byte index;
+
+  EncryptionType(String extensionName, byte index) {
+    this.extensionName = extensionName;
+    this.index = index;
+  }
+
+  /**
+   * deserialize byte number.
+   *
+   * @param encryptor byte number
+   * @return CompressionType
+   * @throws IllegalArgumentException illegal argument
+   */
+  public static EncryptionType deserialize(byte encryptor) {
+    switch (encryptor) {
+      case 0:
+        return EncryptionType.UNENCRYPTED;
+      case 1:
+        return EncryptionType.SM4128;
+      case 2:
+        return EncryptionType.AES128;
+      default:
+        throw new IllegalArgumentException("Invalid input: " + encryptor);
+    }
+  }
+
+  public static int getSerializedSize() {
+    return Byte.BYTES;
+  }
+
+  /**
+   * get serialized size.
+   *
+   * @return byte of index
+   */
+  public byte serialize() {
+    return this.index;
+  }
+
+  /**
+   * get extension.
+   *
+   * @return extension (string type), for example: SM4-128、AES-128

Review Comment:
   The definitions above do not contain "-," be consistent.



##########
java/tsfile/src/main/java/org/apache/tsfile/encrypt/SM4.java:
##########
@@ -0,0 +1,578 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.exception.encrypt.EncryptException;
+import org.apache.tsfile.exception.encrypt.EncryptKeyLengthNotMatchException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class SM4 {
+  public static final int SM4_ENCRYPT = 1;
+
+  public static final int SM4_DECRYPT = 0;
+
+  private long GET_ULONG_BE(byte[] b, int i) {
+    long n =
+        (long) (b[i] & 0xff) << 24
+            | (long) ((b[i + 1] & 0xff) << 16)
+            | (long) ((b[i + 2] & 0xff) << 8)
+            | (long) (b[i + 3] & 0xff) & 0xffffffffL;
+    return n;
+  }
+
+  private void PUT_ULONG_BE(long n, byte[] b, int i) {
+    b[i] = (byte) (int) (0xFF & n >> 24);
+    b[i + 1] = (byte) (int) (0xFF & n >> 16);
+    b[i + 2] = (byte) (int) (0xFF & n >> 8);
+    b[i + 3] = (byte) (int) (0xFF & n);
+  }
+
+  private long SHL(long x, int n) {
+    return (x & 0xFFFFFFFF) << n;
+  }
+
+  private long ROTL(long x, int n) {
+    return SHL(x, n) | x >> (32 - n);
+  }
+
+  private void SWAP(long[] sk, int i) {
+    long t = sk[i];
+    sk[i] = sk[(31 - i)];
+    sk[(31 - i)] = t;
+  }
+
+  public static final byte[] SboxTable = {
+    (byte) 0xd6,
+    (byte) 0x90,
+    (byte) 0xe9,
+    (byte) 0xfe,
+    (byte) 0xcc,
+    (byte) 0xe1,
+    0x3d,
+    (byte) 0xb7,
+    0x16,
+    (byte) 0xb6,
+    0x14,
+    (byte) 0xc2,
+    0x28,
+    (byte) 0xfb,
+    0x2c,
+    0x05,
+    0x2b,
+    0x67,
+    (byte) 0x9a,
+    0x76,
+    0x2a,
+    (byte) 0xbe,
+    0x04,
+    (byte) 0xc3,
+    (byte) 0xaa,
+    0x44,
+    0x13,
+    0x26,
+    0x49,
+    (byte) 0x86,
+    0x06,
+    (byte) 0x99,
+    (byte) 0x9c,
+    0x42,
+    0x50,
+    (byte) 0xf4,
+    (byte) 0x91,
+    (byte) 0xef,
+    (byte) 0x98,
+    0x7a,
+    0x33,
+    0x54,
+    0x0b,
+    0x43,
+    (byte) 0xed,
+    (byte) 0xcf,
+    (byte) 0xac,
+    0x62,
+    (byte) 0xe4,
+    (byte) 0xb3,
+    0x1c,
+    (byte) 0xa9,
+    (byte) 0xc9,
+    0x08,
+    (byte) 0xe8,
+    (byte) 0x95,
+    (byte) 0x80,
+    (byte) 0xdf,
+    (byte) 0x94,
+    (byte) 0xfa,
+    0x75,
+    (byte) 0x8f,
+    0x3f,
+    (byte) 0xa6,
+    0x47,
+    0x07,
+    (byte) 0xa7,
+    (byte) 0xfc,
+    (byte) 0xf3,
+    0x73,
+    0x17,
+    (byte) 0xba,
+    (byte) 0x83,
+    0x59,
+    0x3c,
+    0x19,
+    (byte) 0xe6,
+    (byte) 0x85,
+    0x4f,
+    (byte) 0xa8,
+    0x68,
+    0x6b,
+    (byte) 0x81,
+    (byte) 0xb2,
+    0x71,
+    0x64,
+    (byte) 0xda,
+    (byte) 0x8b,
+    (byte) 0xf8,
+    (byte) 0xeb,
+    0x0f,
+    0x4b,
+    0x70,
+    0x56,
+    (byte) 0x9d,
+    0x35,
+    0x1e,
+    0x24,
+    0x0e,
+    0x5e,
+    0x63,
+    0x58,
+    (byte) 0xd1,
+    (byte) 0xa2,
+    0x25,
+    0x22,
+    0x7c,
+    0x3b,
+    0x01,
+    0x21,
+    0x78,
+    (byte) 0x87,
+    (byte) 0xd4,
+    0x00,
+    0x46,
+    0x57,
+    (byte) 0x9f,
+    (byte) 0xd3,
+    0x27,
+    0x52,
+    0x4c,
+    0x36,
+    0x02,
+    (byte) 0xe7,
+    (byte) 0xa0,
+    (byte) 0xc4,
+    (byte) 0xc8,
+    (byte) 0x9e,
+    (byte) 0xea,
+    (byte) 0xbf,
+    (byte) 0x8a,
+    (byte) 0xd2,
+    0x40,
+    (byte) 0xc7,
+    0x38,
+    (byte) 0xb5,
+    (byte) 0xa3,
+    (byte) 0xf7,
+    (byte) 0xf2,
+    (byte) 0xce,
+    (byte) 0xf9,
+    0x61,
+    0x15,
+    (byte) 0xa1,
+    (byte) 0xe0,
+    (byte) 0xae,
+    0x5d,
+    (byte) 0xa4,
+    (byte) 0x9b,
+    0x34,
+    0x1a,
+    0x55,
+    (byte) 0xad,
+    (byte) 0x93,
+    0x32,
+    0x30,
+    (byte) 0xf5,
+    (byte) 0x8c,
+    (byte) 0xb1,
+    (byte) 0xe3,
+    0x1d,
+    (byte) 0xf6,
+    (byte) 0xe2,
+    0x2e,
+    (byte) 0x82,
+    0x66,
+    (byte) 0xca,
+    0x60,
+    (byte) 0xc0,
+    0x29,
+    0x23,
+    (byte) 0xab,
+    0x0d,
+    0x53,
+    0x4e,
+    0x6f,
+    (byte) 0xd5,
+    (byte) 0xdb,
+    0x37,
+    0x45,
+    (byte) 0xde,
+    (byte) 0xfd,
+    (byte) 0x8e,
+    0x2f,
+    0x03,
+    (byte) 0xff,
+    0x6a,
+    0x72,
+    0x6d,
+    0x6c,
+    0x5b,
+    0x51,
+    (byte) 0x8d,
+    0x1b,
+    (byte) 0xaf,
+    (byte) 0x92,
+    (byte) 0xbb,
+    (byte) 0xdd,
+    (byte) 0xbc,
+    0x7f,
+    0x11,
+    (byte) 0xd9,
+    0x5c,
+    0x41,
+    0x1f,
+    0x10,
+    0x5a,
+    (byte) 0xd8,
+    0x0a,
+    (byte) 0xc1,
+    0x31,
+    (byte) 0x88,
+    (byte) 0xa5,
+    (byte) 0xcd,
+    0x7b,
+    (byte) 0xbd,
+    0x2d,
+    0x74,
+    (byte) 0xd0,
+    0x12,
+    (byte) 0xb8,
+    (byte) 0xe5,
+    (byte) 0xb4,
+    (byte) 0xb0,
+    (byte) 0x89,
+    0x69,
+    (byte) 0x97,
+    0x4a,
+    0x0c,
+    (byte) 0x96,
+    0x77,
+    0x7e,
+    0x65,
+    (byte) 0xb9,
+    (byte) 0xf1,
+    0x09,
+    (byte) 0xc5,
+    0x6e,
+    (byte) 0xc6,
+    (byte) 0x84,
+    0x18,
+    (byte) 0xf0,
+    0x7d,
+    (byte) 0xec,
+    0x3a,
+    (byte) 0xdc,
+    0x4d,
+    0x20,
+    0x79,
+    (byte) 0xee,
+    0x5f,
+    0x3e,
+    (byte) 0xd7,
+    (byte) 0xcb,
+    0x39,
+    0x48
+  };
+
+  public static final int[] FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 
0xb27022dc};
+
+  public static final int[] CK = {
+    0x00070e15,
+    0x1c232a31,
+    0x383f464d,
+    0x545b6269,
+    0x70777e85,
+    0x8c939aa1,
+    0xa8afb6bd,
+    0xc4cbd2d9,
+    0xe0e7eef5,
+    0xfc030a11,
+    0x181f262d,
+    0x343b4249,
+    0x50575e65,
+    0x6c737a81,
+    0x888f969d,
+    0xa4abb2b9,
+    0xc0c7ced5,
+    0xdce3eaf1,
+    0xf8ff060d,
+    0x141b2229,
+    0x30373e45,
+    0x4c535a61,
+    0x686f767d,
+    0x848b9299,
+    0xa0a7aeb5,
+    0xbcc3cad1,
+    0xd8dfe6ed,
+    0xf4fb0209,
+    0x10171e25,
+    0x2c333a41,
+    0x484f565d,
+    0x646b7279
+  };
+
+  private byte sm4Sbox(byte inch) {
+    int i = inch & 0xFF;
+    byte retVal = SboxTable[i];
+    return retVal;
+  }
+
+  private long sm4Lt(long ka) {
+    long bb = 0L;
+    long c = 0L;
+    byte[] a = new byte[4];
+    byte[] b = new byte[4];
+    PUT_ULONG_BE(ka, a, 0);
+    b[0] = sm4Sbox(a[0]);
+    b[1] = sm4Sbox(a[1]);
+    b[2] = sm4Sbox(a[2]);
+    b[3] = sm4Sbox(a[3]);
+    bb = GET_ULONG_BE(b, 0);
+    c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
+    return c;
+  }
+
+  private long sm4F(long x0, long x1, long x2, long x3, long rk) {
+    return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
+  }
+
+  private long sm4CalciRK(long ka) {
+    long bb = 0L;
+    long rk = 0L;
+    byte[] a = new byte[4];
+    byte[] b = new byte[4];
+    PUT_ULONG_BE(ka, a, 0);
+    b[0] = sm4Sbox(a[0]);
+    b[1] = sm4Sbox(a[1]);
+    b[2] = sm4Sbox(a[2]);
+    b[3] = sm4Sbox(a[3]);
+    bb = GET_ULONG_BE(b, 0);
+    rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
+    return rk;
+  }
+
+  private void sm4_setkey(long[] SK, byte[] key) {
+    long[] MK = new long[4];
+    long[] k = new long[36];
+    int i = 0;
+    MK[0] = GET_ULONG_BE(key, 0);
+    MK[1] = GET_ULONG_BE(key, 4);
+    MK[2] = GET_ULONG_BE(key, 8);
+    MK[3] = GET_ULONG_BE(key, 12);
+    k[0] = MK[0] ^ (long) FK[0];
+    k[1] = MK[1] ^ (long) FK[1];
+    k[2] = MK[2] ^ (long) FK[2];
+    k[3] = MK[3] ^ (long) FK[3];
+    for (; i < 32; i++) {
+      k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ 
(long) CK[i]));
+      SK[i] = k[(i + 4)];
+    }
+  }
+
+  private void sm4_one_round(long[] sk, byte[] input, byte[] output) {
+    int i = 0;
+    long[] ulbuf = new long[36];
+    ulbuf[0] = GET_ULONG_BE(input, 0);
+    ulbuf[1] = GET_ULONG_BE(input, 4);
+    ulbuf[2] = GET_ULONG_BE(input, 8);
+    ulbuf[3] = GET_ULONG_BE(input, 12);
+    while (i < 32) {
+      ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i 
+ 3)], sk[i]);
+      i++;
+    }
+    PUT_ULONG_BE(ulbuf[35], output, 0);
+    PUT_ULONG_BE(ulbuf[34], output, 4);
+    PUT_ULONG_BE(ulbuf[33], output, 8);
+    PUT_ULONG_BE(ulbuf[32], output, 12);
+  }
+
+  private byte[] padding(byte[] input, int mode) {
+    if (input == null) {
+      return null;
+    }
+
+    byte[] ret = (byte[]) null;
+    if (mode == SM4_ENCRYPT) {
+      int p = 16 - input.length % 16;
+      ret = new byte[input.length + p];
+      System.arraycopy(input, 0, ret, 0, input.length);
+      for (int i = 0; i < p; i++) {
+        ret[input.length + i] = (byte) p;
+      }
+    } else {
+      int p = input[input.length - 1];
+      ret = new byte[input.length - p];
+      System.arraycopy(input, 0, ret, 0, input.length - p);
+    }
+    return ret;
+  }
+
+  public void sm4_setkey_enc(SM4_Context ctx, byte[] key) {
+    if (ctx == null) {
+      throw new EncryptException("sm4 ctx is null!");
+    }
+
+    if (key == null || key.length != 16) {
+      throw new EncryptException("sm4 key error!");
+    }
+
+    ctx.mode = SM4_ENCRYPT;
+    sm4_setkey(ctx.sk, key);
+  }
+
+  public void sm4_setkey_dec(SM4_Context ctx, byte[] key) {
+    if (ctx == null) {
+      throw new EncryptException("sm4 ctx is null!");
+    }
+
+    if (key == null) {
+      throw new EncryptException("sm4 key null error!");
+    }
+    if (key.length != 16) {
+      throw new EncryptKeyLengthNotMatchException(key.length, 16);
+    }

Review Comment:
   The exception handling below is more clear than above, use it.



##########
java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java:
##########
@@ -1774,14 +1820,45 @@ public ByteBuffer readCompressedPage(PageHeader header) 
throws IOException {
 
   public ByteBuffer readPage(PageHeader header, CompressionType type) throws 
IOException {
     ByteBuffer buffer = readData(-1, header.getCompressedSize());
-    if (header.getUncompressedSize() == 0 || type == 
CompressionType.UNCOMPRESSED) {
+    IDecryptor decryptor = getDecryptor();
+    if (header.getUncompressedSize() == 0) {
       return buffer;
-    } // FIXME if the buffer is not array-implemented.
-    IUnCompressor unCompressor = IUnCompressor.getUnCompressor(type);
-    ByteBuffer uncompressedBuffer = 
ByteBuffer.allocate(header.getUncompressedSize());
-    unCompressor.uncompress(
-        buffer.array(), buffer.position(), buffer.remaining(), 
uncompressedBuffer.array(), 0);
-    return uncompressedBuffer;
+    }
+    if (decryptor == null || decryptor.getEncryptionType() == 
EncryptionType.UNENCRYPTED) {
+      if (type == CompressionType.UNCOMPRESSED) {
+        return buffer;
+      } else {
+        IUnCompressor unCompressor = IUnCompressor.getUnCompressor(type);
+        ByteBuffer uncompressedBuffer = 
ByteBuffer.allocate(header.getUncompressedSize());
+        unCompressor.uncompress(
+            buffer.array(), buffer.position(), buffer.remaining(), 
uncompressedBuffer.array(), 0);
+        return uncompressedBuffer;
+      }
+    } else {
+      if (type == CompressionType.UNCOMPRESSED) {
+        ByteBuffer decryptedBuffer = 
ByteBuffer.allocate(header.getUncompressedSize());
+        System.arraycopy(
+            decryptor.decrypt(buffer.array(), buffer.position(), 
buffer.remaining()),
+            0,
+            decryptedBuffer.array(),
+            0,
+            buffer.remaining());
+        return decryptedBuffer;
+      } else {
+        ByteBuffer decryptedBuffer = 
ByteBuffer.allocate(header.getCompressedSize());
+        System.arraycopy(
+            decryptor.decrypt(buffer.array(), buffer.position(), 
buffer.remaining()),
+            0,
+            decryptedBuffer.array(),
+            0,
+            buffer.remaining());
+        IUnCompressor unCompressor = IUnCompressor.getUnCompressor(type);
+        ByteBuffer uncompressedBuffer = 
ByteBuffer.allocate(header.getUncompressedSize());
+        unCompressor.uncompress(
+            decryptedBuffer.array(), 0, buffer.remaining(), 
uncompressedBuffer.array(), 0);
+        return uncompressedBuffer;
+      }
+    }

Review Comment:
   How about breaking down into two steps:
   ```
   buffer = decrypt(buffer);
   buffer = uncompress(buffer);
   ```
   Mixing the the two up makes it more complicated than needed.



##########
java/tsfile/src/main/java/org/apache/tsfile/read/reader/chunk/ChunkReader.java:
##########
@@ -163,17 +167,32 @@ public static ByteBuffer 
readCompressedPageData(PageHeader pageHeader, ByteBuffe
   }
 
   public static ByteBuffer uncompressPageData(
-      PageHeader pageHeader, IUnCompressor unCompressor, ByteBuffer 
compressedPageData)
+      PageHeader pageHeader,
+      IUnCompressor unCompressor,
+      ByteBuffer compressedPageData,
+      IDecryptor decryptor)
       throws IOException {
     int compressedPageBodyLength = pageHeader.getCompressedSize();
     byte[] uncompressedPageData = new byte[pageHeader.getUncompressedSize()];
+    byte[] decryptedPageData = new byte[pageHeader.getCompressedSize()];
     try {
+      //      unCompressor.uncompress(
+      //          compressedPageData.array(),
+      //          compressedPageData.arrayOffset() + 
compressedPageData.position(),
+      //          compressedPageBodyLength,
+      //          uncompressedPageData,
+      //          0);

Review Comment:
   Remove



##########
java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java:
##########
@@ -56,11 +62,64 @@ public Chunk(
     this.chunkData = buffer;
     this.deleteIntervalList = deleteIntervalList;
     this.chunkStatistic = chunkStatistic;
+    if (TSFileDescriptor.getInstance().getConfig().getEncryptFlag()) {
+      try {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update("IoTDB is the best".getBytes());
+        
md.update(TSFileDescriptor.getInstance().getConfig().getEncryptKey().getBytes());
+        byte[] tem = md.digest();
+        this.decryptor =
+            IDecryptor.getDecryptor(
+                TSFileDescriptor.getInstance().getConfig().getEncryptType(), 
tem);
+      } catch (Exception e) {
+        throw new EncryptException("md5 function not found while use md5 to 
generate data key");
+      }
+    } else {
+      this.decryptor = IDecryptor.getDecryptor("UNENCRYPTED", null);
+    }

Review Comment:
   This code seems to repeat, may extract it as a util function.



##########
java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java:
##########
@@ -355,6 +359,39 @@ public BloomFilter readBloomFilter() throws IOException {
     return tsFileMetaData.getBloomFilter();
   }
 
+  /**
+   * Retrieves the decryptor for the TsFile. This method reads the file 
metadata to obtain the
+   * decryptor information. If an error occurs while reading the metadata, it 
logs the error and
+   * attempts to retrieve the decryptor based on the configuration settings.
+   *
+   * @return the decryptor for the TsFile
+   * @throws IOException if an I/O error occurs while reading the file metadata
+   */
+  public IDecryptor getDecryptor() throws IOException {
+    try {
+      readFileMetadata();
+    } catch (Exception e) {
+      String encryptType;

Review Comment:
   "it logs the error"?



##########
java/tsfile/src/main/java/org/apache/tsfile/write/writer/TsFileIOWriter.java:
##########
@@ -139,6 +148,72 @@ public TsFileIOWriter(File file) throws IOException {
     if (resourceLogger.isDebugEnabled()) {
       resourceLogger.debug("{} writer is opened.", file.getName());
     }
+    if (TS_FILE_CONFIG.getEncryptFlag()) {
+      this.encryptLevel = "2";
+      this.encryptType = TS_FILE_CONFIG.getEncryptType();
+      try {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update("IoTDB is the best".getBytes());
+        md.update(TS_FILE_CONFIG.getEncryptKey().getBytes());
+        byte[] tem = md.digest();
+        byte[] tem1 =
+            IEncryptor.getEncryptor(
+                    TS_FILE_CONFIG.getEncryptType(), 
TS_FILE_CONFIG.getEncryptKey().getBytes())
+                .encrypt(tem);
+        StringBuilder valueStr = new StringBuilder();
+
+        for (byte b : tem1) {
+          valueStr.append(b).append(",");
+        }
+
+        valueStr.deleteCharAt(valueStr.length() - 1);
+        String str = valueStr.toString();
+
+        this.encryptKey = str;
+      } catch (Exception e) {
+        throw new EncryptException("md5 function not found while use md5 to 
generate data key");
+      }
+    } else {
+      this.encryptLevel = "0";
+      this.encryptType = "UNENCRYPTED";
+      this.encryptKey = null;
+    }
+    startFile();
+  }
+
+  /** for test only */
+  public TsFileIOWriter(File file, TSFileConfig conf) throws IOException {
+    this.out = 
FSFactoryProducer.getFileOutputFactory().getTsFileOutput(file.getPath(), false);

Review Comment:
   The method above may call `this(file, TS_FILE_CONFIG)` to avoid redundancy.



##########
java/tsfile/src/main/java/org/apache/tsfile/write/TsFileWriter.java:
##########
@@ -69,6 +72,16 @@ public class TsFileWriter implements AutoCloseable {
   /** IO writer of this TsFile. */
   private final TsFileIOWriter fileWriter;
 
+  private String encryptLevel;
+
+  private String encryptType;
+
+  private byte[] encryptKey;
+
+  private byte[] dataEncryptKey;

Review Comment:
   The naming is not very clear.
   How about `levelTwoEncryptKey` and `levelOneEncryptKey` and add some 
comments?



##########
java/tsfile/src/main/java/org/apache/tsfile/write/chunk/ChunkWriterImpl.java:
##########
@@ -99,6 +104,21 @@ public class ChunkWriterImpl implements IChunkWriter {
   public ChunkWriterImpl(IMeasurementSchema schema) {
     this.measurementSchema = schema;
     this.compressor = ICompressor.getCompressor(schema.getCompressor());
+    if (TSFileDescriptor.getInstance().getConfig().getEncryptFlag()) {
+      try {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update("IoTDB is the best".getBytes());
+        
md.update(TSFileDescriptor.getInstance().getConfig().getEncryptKey().getBytes());
+        byte[] tem = md.digest();
+        this.encryptor =
+            IEncryptor.getEncryptor(
+                TSFileDescriptor.getInstance().getConfig().getEncryptType(), 
tem);
+      } catch (Exception e) {
+        throw new EncryptException("md5 function not found while use md5 to 
generate data key");
+      }
+    } else {
+      this.encryptor = IEncryptor.getEncryptor("UNENCRYPTED", null);
+    }
     this.pageBuffer = new PublicBAOS();
 
     this.pageSizeThreshold = 
TSFileDescriptor.getInstance().getConfig().getPageSizeInByte();

Review Comment:
   These constructors for compatibility are highly redundant, may use:
   ```
   this(schema, EncryptUtils.getDefaultEncryptor());
   ``` 
   Check other places.



##########
java/tsfile/src/main/java/org/apache/tsfile/write/page/PageWriter.java:
##########
@@ -214,6 +254,10 @@ public int writePageHeaderAndDataIntoBuff(PublicBAOS 
pageBuffer, boolean first)
     int compressedSize;
     byte[] compressedBytes = null;
 
+    if (encryptor.getEncryptionType() == EncryptionType.UNENCRYPTED) {
+      logger.debug("encryptor is unencrypted");
+    }
+

Review Comment:
   Remove



##########
java/tsfile/src/test/java/org/apache/tsfile/encrypt/AES128TsFileReadWriteTest.java:
##########
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.common.conf.TSFileDescriptor;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.exception.write.WriteProcessException;
+import org.apache.tsfile.file.metadata.IDeviceID;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.read.TsFileReader;
+import org.apache.tsfile.read.TsFileSequenceReader;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.Path;
+import org.apache.tsfile.read.common.RowRecord;
+import org.apache.tsfile.read.expression.QueryExpression;
+import org.apache.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.tsfile.utils.TsFileGeneratorForTest;
+import org.apache.tsfile.write.TsFileWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.DoubleDataPoint;
+import org.apache.tsfile.write.record.datapoint.FloatDataPoint;
+import org.apache.tsfile.write.record.datapoint.IntDataPoint;
+import org.apache.tsfile.write.record.datapoint.LongDataPoint;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.apache.tsfile.write.schema.Schema;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class AES128TsFileReadWriteTest {
+  private final double delta = 0.0000001;
+  private final String path = 
TsFileGeneratorForTest.getTestTsFilePath("root.sg1", 0, 0, 1);
+  private File f;
+  private final IDeviceID deviceID = 
IDeviceID.Factory.DEFAULT_FACTORY.create("device_1");
+
+  private TSFileConfig conf = TSFileDescriptor.getInstance().getConfig();
+
+  @Before
+  public void prepare() throws IOException {
+    conf.setEncryptFlag("true");
+    conf.setEncryptType("AES128");
+    conf.setEncryptKey("thisisourtestkey");
+  }
+
+  @Before
+  public void setUp() {
+    f = new File(path);
+    if (f.exists()) {
+      assertTrue(f.delete());
+    }
+    if (!f.getParentFile().exists()) {
+      assertTrue(f.getParentFile().mkdirs());
+    }
+  }
+
+  @After
+  public void tearDown() {
+    f = new File(path);
+    if (f.exists()) {
+      assertTrue(f.delete());
+    }
+  }
+
+  @After
+  public void end() {
+    conf.setEncryptKey("abcdefghijklmnop");
+    conf.setEncryptType("UNENCRYPTED");
+    conf.setEncryptFlag("false");
+  }
+
+  @Test
+  public void intTest() throws IOException, WriteProcessException {
+    List<TSEncoding> encodings =
+        Arrays.asList(
+            TSEncoding.PLAIN,
+            TSEncoding.RLE,
+            TSEncoding.TS_2DIFF,
+            TSEncoding.REGULAR,
+            TSEncoding.GORILLA,
+            TSEncoding.ZIGZAG);
+    for (TSEncoding encoding : encodings) {
+      intTest(encoding);
+    }
+  }
+
+  private void intTest(TSEncoding encoding) throws IOException, 
WriteProcessException {
+    writeDataByTSRecord(TSDataType.INT32, (i) -> new IntDataPoint("sensor_1", 
(int) i), encoding);
+    readData((i, field, delta) -> assertEquals(i, field.getIntV()));
+  }
+
+  @Test
+  public void longTest() throws IOException, WriteProcessException {
+    List<TSEncoding> encodings =
+        Arrays.asList(
+            TSEncoding.PLAIN,
+            TSEncoding.RLE,
+            TSEncoding.TS_2DIFF,
+            TSEncoding.REGULAR,
+            TSEncoding.GORILLA);
+    for (TSEncoding encoding : encodings) {
+      longTest(encoding);
+    }
+  }
+
+  public void longTest(TSEncoding encoding) throws IOException, 
WriteProcessException {
+    writeDataByTSRecord(TSDataType.INT64, (i) -> new LongDataPoint("sensor_1", 
i), encoding);
+    readData((i, field, delta) -> assertEquals(i, field.getLongV()));
+  }
+
+  @Test
+  public void floatTest() throws IOException, WriteProcessException {
+    List<TSEncoding> encodings =
+        Arrays.asList(
+            TSEncoding.PLAIN,
+            TSEncoding.RLE,
+            TSEncoding.TS_2DIFF,
+            TSEncoding.GORILLA_V1,
+            TSEncoding.GORILLA);
+    for (TSEncoding encoding : encodings) {
+      floatTest(encoding);
+    }
+  }
+
+  public void floatTest(TSEncoding encoding) throws IOException, 
WriteProcessException {
+    writeDataByTSRecord(
+        TSDataType.FLOAT, (i) -> new FloatDataPoint("sensor_1", (float) i), 
encoding);
+    readData((i, field, delta) -> assertEquals(i, field.getFloatV(), delta));
+  }
+
+  @Test
+  public void doubleTest() throws IOException, WriteProcessException {
+    List<TSEncoding> encodings =
+        Arrays.asList(
+            TSEncoding.PLAIN,
+            TSEncoding.RLE,
+            TSEncoding.TS_2DIFF,
+            TSEncoding.GORILLA_V1,
+            TSEncoding.GORILLA);
+    for (TSEncoding encoding : encodings) {
+      doubleTest(encoding);
+    }
+  }
+
+  public void doubleTest(TSEncoding encoding) throws IOException, 
WriteProcessException {
+    writeDataByTSRecord(
+        TSDataType.DOUBLE, (i) -> new DoubleDataPoint("sensor_1", (double) i), 
encoding);
+    readData((i, field, delta) -> assertEquals(i, field.getDoubleV(), delta));
+  }
+
+  // If no dataPoint in "device_1.sensor_2", it will throws a nomeasurement
+  // exception,
+  // cause no schema in tsfilemetadata anymore.
+  @Test
+  public void readEmptyMeasurementTest() throws IOException, 
WriteProcessException {
+    try (TsFileWriter tsFileWriter = new TsFileWriter(f, new Schema(), conf)) {
+      // add measurements into file schema
+      tsFileWriter.registerTimeseries(
+          new Path(deviceID), new MeasurementSchema("sensor_1", 
TSDataType.FLOAT, TSEncoding.RLE));
+      tsFileWriter.registerTimeseries(
+          new Path(deviceID),
+          new MeasurementSchema("sensor_2", TSDataType.INT32, 
TSEncoding.TS_2DIFF));
+      // construct TSRecord
+      TSRecord tsRecord = new TSRecord(1, deviceID);
+      DataPoint dPoint1 = new FloatDataPoint("sensor_1", 1.2f);
+      tsRecord.addTuple(dPoint1);
+      // write a TSRecord to TsFile
+      tsFileWriter.write(tsRecord);
+    }
+
+    // read example : no filter
+    TsFileSequenceReader reader = new TsFileSequenceReader(path);
+    TsFileReader readTsFile = new TsFileReader(reader);
+    ArrayList<Path> paths = new ArrayList<>();
+    paths.add(new Path(deviceID, "sensor_2", true));
+    QueryExpression queryExpression = QueryExpression.create(paths, null);
+    try {
+      QueryDataSet queryDataSet = readTsFile.query(queryExpression);
+    } catch (IOException e) {
+      // Assert.fail();

Review Comment:
   Why ignore the exception?



##########
java/tsfile/src/main/java/org/apache/tsfile/write/writer/TsFileIOWriter.java:
##########
@@ -164,6 +239,20 @@ public TsFileIOWriter(File file, long maxMetadataSize) 
throws IOException {
     chunkMetadataTempFile = new File(file.getAbsolutePath() + 
CHUNK_METADATA_TEMP_FILE_SUFFIX);
   }
 
+  public String getFileName() {
+    if (file != null) {
+      return file.getName();
+    } else {
+      return "jshegdhdjfhdhmnb";
+    }
+  }

Review Comment:
   What is this?



##########
java/tsfile/src/test/java/org/apache/tsfile/encrypt/AES128TsFileReadWriteTest.java:
##########
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tsfile.encrypt;
+
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.common.conf.TSFileDescriptor;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.exception.write.WriteProcessException;
+import org.apache.tsfile.file.metadata.IDeviceID;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.read.TsFileReader;
+import org.apache.tsfile.read.TsFileSequenceReader;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.Path;
+import org.apache.tsfile.read.common.RowRecord;
+import org.apache.tsfile.read.expression.QueryExpression;
+import org.apache.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.tsfile.utils.TsFileGeneratorForTest;
+import org.apache.tsfile.write.TsFileWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.DoubleDataPoint;
+import org.apache.tsfile.write.record.datapoint.FloatDataPoint;
+import org.apache.tsfile.write.record.datapoint.IntDataPoint;
+import org.apache.tsfile.write.record.datapoint.LongDataPoint;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.apache.tsfile.write.schema.Schema;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class AES128TsFileReadWriteTest {
+  private final double delta = 0.0000001;
+  private final String path = 
TsFileGeneratorForTest.getTestTsFilePath("root.sg1", 0, 0, 1);
+  private File f;
+  private final IDeviceID deviceID = 
IDeviceID.Factory.DEFAULT_FACTORY.create("device_1");
+
+  private TSFileConfig conf = TSFileDescriptor.getInstance().getConfig();
+
+  @Before
+  public void prepare() throws IOException {
+    conf.setEncryptFlag("true");
+    conf.setEncryptType("AES128");
+    conf.setEncryptKey("thisisourtestkey");
+  }
+
+  @Before
+  public void setUp() {
+    f = new File(path);
+    if (f.exists()) {
+      assertTrue(f.delete());
+    }
+    if (!f.getParentFile().exists()) {
+      assertTrue(f.getParentFile().mkdirs());
+    }
+  }
+
+  @After
+  public void tearDown() {
+    f = new File(path);
+    if (f.exists()) {
+      assertTrue(f.delete());
+    }
+  }
+
+  @After
+  public void end() {
+    conf.setEncryptKey("abcdefghijklmnop");
+    conf.setEncryptType("UNENCRYPTED");
+    conf.setEncryptFlag("false");
+  }

Review Comment:
   How about merging two Befores and two Afters?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to