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

zqr10159 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new 6152c07320 refactor: evolve common-core payload compatibility (#4237)
6152c07320 is described below

commit 6152c07320c5a883b7ac9b14e6cb662c488bfaee
Author: Logic <[email protected]>
AuthorDate: Fri Jul 24 15:07:35 2026 +0800

    refactor: evolve common-core payload compatibility (#4237)
---
 .../org/apache/hertzbeat/common/util/AesUtil.java  | 49 +++++++++++++++++++---
 .../apache/hertzbeat/common/util/AesUtilTest.java  | 23 ++++++++++
 2 files changed, 67 insertions(+), 5 deletions(-)

diff --git 
a/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/util/AesUtil.java
 
b/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/util/AesUtil.java
index fd1279b809..b9b63579a5 100644
--- 
a/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/util/AesUtil.java
+++ 
b/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/util/AesUtil.java
@@ -17,8 +17,11 @@
 
 package org.apache.hertzbeat.common.util;
 
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
 import java.util.Base64;
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
@@ -46,6 +49,12 @@ public final class AesUtil {
 
     private static final String AES = "AES";
 
+    private static final byte[] PAYLOAD_HEADER = {'H', 'B', 'A', '2'};
+
+    private static final int IV_LENGTH = 16;
+
+    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
+
     /**
      * Encryption key The AES encryption key is 16 bits.
      * If the AES encryption key is larger than 16 bits, an error message is 
displayed
@@ -87,14 +96,21 @@ public final class AesUtil {
             SecretKeySpec keySpec = new 
SecretKeySpec(encryptKey.getBytes(StandardCharsets.UTF_8), AES);
             // cipher based on the algorithm AES
             Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
+            byte[] initializationVector = new byte[IV_LENGTH];
+            SECURE_RANDOM.nextBytes(initializationVector);
             // init cipher Encrypt_mode or Decrypt_mode operation, the second 
parameter is the KEY used
-            cipher.init(Cipher.ENCRYPT_MODE, keySpec, new 
IvParameterSpec(encryptKey.getBytes(StandardCharsets.UTF_8)));
+            cipher.init(Cipher.ENCRYPT_MODE, keySpec, new 
IvParameterSpec(initializationVector));
             // get content bytes, must utf-8
             byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
             // encode content to byte array
             byte[] byteAes = cipher.doFinal(byteEncode);
+            byte[] payload = ByteBuffer.allocate(PAYLOAD_HEADER.length + 
initializationVector.length + byteAes.length)
+                    .put(PAYLOAD_HEADER)
+                    .put(initializationVector)
+                    .put(byteAes)
+                    .array();
             // base64 encode content
-            return Base64.getEncoder().encodeToString(byteAes);
+            return Base64.getEncoder().encodeToString(payload);
         } catch (Exception e) {
             log.error("aes encode content error: {}", e.getMessage(), e);
             return content;
@@ -135,13 +151,36 @@ public final class AesUtil {
         SecretKeySpec keySpec = new 
SecretKeySpec(decryptKey.getBytes(StandardCharsets.UTF_8), AES);
         // cipher based on the algorithm AES
         Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
-        // init cipher Encrypt_mode or Decrypt_mode operation, the second 
parameter is the KEY used
-        cipher.init(Cipher.DECRYPT_MODE, keySpec, new 
IvParameterSpec(decryptKey.getBytes(StandardCharsets.UTF_8)));
-        // base64 decode content
         byte[] bytesContent = Base64.getDecoder().decode(content);
+        byte[] initializationVector;
+        if (hasPayloadHeader(bytesContent)) {
+            if (bytesContent.length <= PAYLOAD_HEADER.length + IV_LENGTH) {
+                throw new IllegalArgumentException("Invalid encrypted 
payload");
+            }
+            initializationVector = Arrays.copyOfRange(
+                    bytesContent, PAYLOAD_HEADER.length, PAYLOAD_HEADER.length 
+ IV_LENGTH);
+            bytesContent = Arrays.copyOfRange(
+                    bytesContent, PAYLOAD_HEADER.length + IV_LENGTH, 
bytesContent.length);
+        } else {
+            initializationVector = decryptKey.getBytes(StandardCharsets.UTF_8);
+        }
+        // init cipher Encrypt_mode or Decrypt_mode operation, the second 
parameter is the KEY used
+        cipher.init(Cipher.DECRYPT_MODE, keySpec, new 
IvParameterSpec(initializationVector));
         // decode content to byte array
         return cipher.doFinal(bytesContent);
     }
+
+    private static boolean hasPayloadHeader(byte[] payload) {
+        if (payload.length < PAYLOAD_HEADER.length) {
+            return false;
+        }
+        for (int index = 0; index < PAYLOAD_HEADER.length; index++) {
+            if (payload[index] != PAYLOAD_HEADER[index]) {
+                return false;
+            }
+        }
+        return true;
+    }
     
     /**
      * Determine whether it is encrypted
diff --git 
a/hertzbeat-common-core/src/test/java/org/apache/hertzbeat/common/util/AesUtilTest.java
 
b/hertzbeat-common-core/src/test/java/org/apache/hertzbeat/common/util/AesUtilTest.java
index 9bff2d915c..7ff913701c 100644
--- 
a/hertzbeat-common-core/src/test/java/org/apache/hertzbeat/common/util/AesUtilTest.java
+++ 
b/hertzbeat-common-core/src/test/java/org/apache/hertzbeat/common/util/AesUtilTest.java
@@ -20,10 +20,14 @@ package org.apache.hertzbeat.common.util;
 import static org.apache.hertzbeat.common.util.AesUtil.aesDecode;
 import static org.apache.hertzbeat.common.util.AesUtil.aesEncode;
 import static org.apache.hertzbeat.common.util.AesUtil.isCiphertext;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Base64;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -43,12 +47,31 @@ class AesUtilTest {
     void testAesEncode() {
         String originalText = "This is a secret message";
         String encryptedText = aesEncode(originalText, VALID_KEY);
+        String secondEncryptedText = aesEncode(originalText, VALID_KEY);
         assertNotEquals(originalText, encryptedText);
+        assertNotEquals(encryptedText, secondEncryptedText);
+
+        byte[] encryptedPayload = Base64.getDecoder().decode(encryptedText);
+        byte[] secondEncryptedPayload = 
Base64.getDecoder().decode(secondEncryptedText);
+        assertArrayEquals(new byte[] {'H', 'B', 'A', '2'}, 
Arrays.copyOfRange(encryptedPayload, 0, 4));
+        assertFalse(Arrays.equals(
+                VALID_KEY.getBytes(StandardCharsets.UTF_8), 
Arrays.copyOfRange(encryptedPayload, 4, 20)));
+        assertFalse(Arrays.equals(
+                Arrays.copyOfRange(encryptedPayload, 4, 20),
+                Arrays.copyOfRange(secondEncryptedPayload, 4, 20)));
 
         String decryptedText = aesDecode(encryptedText, VALID_KEY);
         assertEquals(originalText, decryptedText);
     }
 
+    @Test
+    void testLegacyCiphertextCanBeDecoded() {
+        String legacyCiphertext = 
"muJNZwhxg173v6EZAXb5TK8L5XlmDE5xmc9XTryH6Qk=";
+
+        assertEquals("This is a secret message", aesDecode(legacyCiphertext, 
VALID_KEY));
+        assertTrue(isCiphertext(legacyCiphertext, VALID_KEY));
+    }
+
     @Test
     void testAesDecode() {
         // Test with invalid key


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to