mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 09:40:58 +00:00
refactor: evolve common-core payload compatibility (#4237)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user