From d8bc6a02a4603bd16a4d6b3e951d89dc65167ed2 Mon Sep 17 00:00:00 2001 From: LXW <1264174498@qq.com> Date: Sun, 30 Jun 2024 16:18:31 +0800 Subject: [PATCH] =?UTF-8?q?(improvement)(common)=20Remove=20AESUtil=20and?= =?UTF-8?q?=20add=20AES/CBC=E3=80=81AES/ECB=20encryption/decryption=20in?= =?UTF-8?q?=20AESEncryptionUtil=20(#1297)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: lxwcodemonkey --- .../config/AuthenticationConfig.java | 2 +- .../adaptor/DefaultUserAdaptor.java | 2 +- .../utils/AESEncryptionUtil.java | 67 --------- .../server/service/impl/AgentServiceImpl.java | 3 +- .../supersonic/common/config/LLMConfig.java | 4 +- .../common/util/AESEncryptionUtil.java | 134 ++++++++++++++++++ .../supersonic/common/util/AESUtil.java | 84 ----------- .../util/AESEncryptionUtilTest.java | 16 ++- 8 files changed, 155 insertions(+), 157 deletions(-) delete mode 100644 auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/AESEncryptionUtil.java create mode 100644 common/src/main/java/com/tencent/supersonic/common/util/AESEncryptionUtil.java delete mode 100644 common/src/main/java/com/tencent/supersonic/common/util/AESUtil.java diff --git a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authentication/config/AuthenticationConfig.java b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authentication/config/AuthenticationConfig.java index db51018a1..3983b0074 100644 --- a/auth/api/src/main/java/com/tencent/supersonic/auth/api/authentication/config/AuthenticationConfig.java +++ b/auth/api/src/main/java/com/tencent/supersonic/auth/api/authentication/config/AuthenticationConfig.java @@ -44,7 +44,7 @@ public class AuthenticationConfig { @Value("${s2.authentication.app.signature:signature}") private String signature; - @Value("${s2.authentication.token.timeout:7200000}") + @Value("${s2.authentication.token.timeout:72000000}") private Long tokenTimeout; public Map getAppKeyToSecretMap() { diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/adaptor/DefaultUserAdaptor.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/adaptor/DefaultUserAdaptor.java index fb94d4dd2..53afe18be 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/adaptor/DefaultUserAdaptor.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/adaptor/DefaultUserAdaptor.java @@ -9,7 +9,7 @@ import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword; import com.tencent.supersonic.auth.api.authentication.request.UserReq; import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO; import com.tencent.supersonic.auth.authentication.persistence.repository.UserRepository; -import com.tencent.supersonic.auth.authentication.utils.AESEncryptionUtil; +import com.tencent.supersonic.common.util.AESEncryptionUtil; import com.tencent.supersonic.auth.authentication.utils.UserTokenUtils; import com.tencent.supersonic.common.util.ContextUtils; import lombok.extern.slf4j.Slf4j; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/AESEncryptionUtil.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/AESEncryptionUtil.java deleted file mode 100644 index 924793083..000000000 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/utils/AESEncryptionUtil.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.tencent.supersonic.auth.authentication.utils; - -import lombok.extern.slf4j.Slf4j; - -import javax.crypto.Cipher; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import java.security.MessageDigest; -import java.security.spec.KeySpec; -import java.util.Base64; - -@Slf4j -public class AESEncryptionUtil { - - private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; - private static final String ENCODE = "UTF-8"; - private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA256"; - private static final int ITERATIONS = 65536; - private static final int KEY_LENGTH = 256; - - public static byte[] generateSalt(String username) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(username.getBytes(ENCODE)); - byte[] hash = md.digest(); - // 通常只需要使用盐的一部分作为盐值,例如16字节 - byte[] salt = new byte[16]; - System.arraycopy(hash, 0, salt, 0, salt.length); - return salt; - } - - public static String encrypt(String password, byte[] salt) throws Exception { - try { - // TODO 固定IV,确保每次加密时使用相同的IV,该值应该安全保管 - byte[] iv = "supersonic@bicom".getBytes(ENCODE); - IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); - - KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH); - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SECRET_KEY_ALGORITHM); - byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded(); - SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); - - Cipher cipher = Cipher.getInstance(ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); - - byte[] encrypted = cipher.doFinal(password.getBytes(ENCODE)); - byte[] combined = new byte[iv.length + encrypted.length]; - System.arraycopy(iv, 0, combined, 0, iv.length); - System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length); - - return Base64.getEncoder().encodeToString(combined); - } catch (Throwable e) { - log.error("encrypt", e); - throw e; - } - } - - public static String getStringFromBytes(byte[] salt) { - return Base64.getEncoder().encodeToString(salt); - } - - public static byte[] getBytesFromString(String encodeSalt) { - return Base64.getDecoder().decode(encodeSalt); - } - -} \ No newline at end of file diff --git a/chat/server/src/main/java/com/tencent/supersonic/chat/server/service/impl/AgentServiceImpl.java b/chat/server/src/main/java/com/tencent/supersonic/chat/server/service/impl/AgentServiceImpl.java index 62db679e5..c0147788d 100644 --- a/chat/server/src/main/java/com/tencent/supersonic/chat/server/service/impl/AgentServiceImpl.java +++ b/chat/server/src/main/java/com/tencent/supersonic/chat/server/service/impl/AgentServiceImpl.java @@ -89,7 +89,8 @@ public class AgentServiceImpl extends ServiceImpl return; } List examples = agent.getExamples(); - ChatMemoryFilter chatMemoryFilter = ChatMemoryFilter.builder().questions(examples).build(); + ChatMemoryFilter chatMemoryFilter = ChatMemoryFilter.builder().agentId(agent.getId()) + .questions(examples).build(); List memoriesExisted = memoryService.getMemories(chatMemoryFilter) .stream().map(ChatMemoryDO::getQuestion).collect(Collectors.toList()); for (String example : examples) { diff --git a/common/src/main/java/com/tencent/supersonic/common/config/LLMConfig.java b/common/src/main/java/com/tencent/supersonic/common/config/LLMConfig.java index 1754b24db..e7835c924 100644 --- a/common/src/main/java/com/tencent/supersonic/common/config/LLMConfig.java +++ b/common/src/main/java/com/tencent/supersonic/common/config/LLMConfig.java @@ -1,6 +1,6 @@ package com.tencent.supersonic.common.config; -import com.tencent.supersonic.common.util.AESUtil; +import com.tencent.supersonic.common.util.AESEncryptionUtil; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -39,7 +39,7 @@ public class LLMConfig { } public String keyDecrypt() { - return AESUtil.aesDecrypt(apiKey); + return AESEncryptionUtil.aesDecryptECB(apiKey); } } diff --git a/common/src/main/java/com/tencent/supersonic/common/util/AESEncryptionUtil.java b/common/src/main/java/com/tencent/supersonic/common/util/AESEncryptionUtil.java new file mode 100644 index 000000000..2a1bf29b8 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/util/AESEncryptionUtil.java @@ -0,0 +1,134 @@ +package com.tencent.supersonic.common.util; + +import lombok.extern.slf4j.Slf4j; + +import javax.crypto.Cipher; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.spec.KeySpec; +import java.util.Arrays; +import java.util.Base64; + +@Slf4j +public class AESEncryptionUtil { + + private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; + private static final String ENCODE = "UTF-8"; + private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA256"; + private static final int ITERATIONS = 65536; + private static final int KEY_LENGTH = 256; + private static final String KEY = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"; + // TODO 固定IV,确保每次加密时使用相同的IV,该值应该安全保管 + private static final String IV = "supersonic@bicom"; + + public static byte[] generateSalt(String username) throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(username.getBytes(ENCODE)); + byte[] hash = md.digest(); + // 通常只需要使用盐的一部分作为盐值,例如16字节 + byte[] salt = new byte[16]; + System.arraycopy(hash, 0, salt, 0, salt.length); + return salt; + } + + public static String encrypt(String password, byte[] salt) throws Exception { + try { + byte[] iv = IV.getBytes(ENCODE); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + + KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SECRET_KEY_ALGORITHM); + byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded(); + SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); + + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + + byte[] encrypted = cipher.doFinal(password.getBytes(ENCODE)); + byte[] combined = new byte[iv.length + encrypted.length]; + System.arraycopy(iv, 0, combined, 0, iv.length); + System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length); + + return Base64.getEncoder().encodeToString(combined); + } catch (Throwable e) { + log.error("encrypt", e); + throw e; + } + } + + public static String aesDecryptCBC(String encryptStr) { + try { + byte[] combined = Base64.getDecoder().decode(encryptStr); + byte[] iv = Arrays.copyOfRange(combined, 0, 16); + byte[] encryptedData = Arrays.copyOfRange(combined, 16, combined.length); + + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + Cipher cipher = Cipher.getInstance(ALGORITHM); + SecretKeySpec secretKeySpec = new SecretKeySpec(hexStringToByteArray(KEY), "AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] decryptedBytes = cipher.doFinal(encryptedData); + + return new String(decryptedBytes, ENCODE); + } catch (Exception e) { + log.warn("encryptStr decrypt failed:{}", encryptStr); + return encryptStr; + } + } + + public static String aesEncryptCBC(String content) throws Exception { + byte[] iv = IV.getBytes(ENCODE); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + Cipher cipher = Cipher.getInstance(ALGORITHM); + SecretKeySpec secretKeySpec = new SecretKeySpec(hexStringToByteArray(KEY), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encryptEncode = cipher.doFinal(content.getBytes(ENCODE)); + byte[] combined = new byte[iv.length + encryptEncode.length]; + System.arraycopy(iv, 0, combined, 0, iv.length); + System.arraycopy(encryptEncode, 0, combined, iv.length, encryptEncode.length); + return Base64.getEncoder().encodeToString(combined); + } + + public static String aesEncryptECB(String content) throws Exception { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + SecretKeySpec secretKeySpec = new SecretKeySpec(hexStringToByteArray(KEY), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + byte[] encryptEncode = cipher.doFinal(content.getBytes(ENCODE)); + return getStringFromBytes(encryptEncode); + } + + public static String aesDecryptECB(String encryptStr) { + try { + byte[] encryptBytes = getBytesFromString(encryptStr); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + SecretKeySpec secretKeySpec = new SecretKeySpec(hexStringToByteArray(KEY), "AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); + byte[] decryptedBytes = cipher.doFinal(encryptBytes); + return new String(decryptedBytes, ENCODE); + } catch (Exception e) { + log.warn("encryptStr decrypt failed:{}", encryptStr); + return encryptStr; + } + } + + public static byte[] hexStringToByteArray(String hexString) { + int len = hexString.length(); + byte[] byteArray = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + byteArray[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + + Character.digit(hexString.charAt(i + 1), 16)); + } + return byteArray; + } + + public static String getStringFromBytes(byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } + + public static byte[] getBytesFromString(String str) { + return Base64.getDecoder().decode(str); + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/tencent/supersonic/common/util/AESUtil.java b/common/src/main/java/com/tencent/supersonic/common/util/AESUtil.java deleted file mode 100644 index d519fc537..000000000 --- a/common/src/main/java/com/tencent/supersonic/common/util/AESUtil.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.tencent.supersonic.common.util; - - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang3.StringUtils; -import sun.misc.BASE64Decoder; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.spec.SecretKeySpec; - -@Slf4j -public class AESUtil { - - private static final String KEY = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"; - //算法 - private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; - - public static String aesDecrypt(String encrypt) { - try { - return aesDecrypt(encrypt, KEY); - } catch (Exception e) { - log.warn("content decrypt failed:{}", encrypt); - return encrypt; - } - } - - private static String aesDecrypt(String encryptStr, String decryptKey) throws Exception { - return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey); - } - - private static String base64Encode(byte[] bytes) { - return Base64.encodeBase64String(bytes); - } - - private static byte[] base64Decode(String base64Code) throws Exception { - return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code); - } - - private static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { - KeyGenerator kgen = KeyGenerator.getInstance("AES"); - kgen.init(128); - Cipher cipher = Cipher.getInstance(ALGORITHMSTR); - cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(hexStringToByteArray(encryptKey), "AES")); - - return cipher.doFinal(content.getBytes("utf-8")); - } - - private static String aesEncrypt(String content, String encryptKey) throws Exception { - return base64Encode(aesEncryptToBytes(content, encryptKey)); - } - - private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { - KeyGenerator kgen = KeyGenerator.getInstance("AES"); - kgen.init(128); - - Cipher cipher = Cipher.getInstance(ALGORITHMSTR); - cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(hexStringToByteArray(decryptKey), "AES")); - byte[] decryptBytes = cipher.doFinal(encryptBytes); - return new String(decryptBytes); - } - - public static byte[] hexStringToByteArray(String hexString) { - int len = hexString.length(); - byte[] byteArray = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - byteArray[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) - + Character.digit(hexString.charAt(i + 1), 16)); - } - return byteArray; - } - - public static void main(String[] args) throws Exception { - String content = "123"; - System.out.println("before encrypt:" + content); - System.out.println("key:" + KEY); - String encrypt = aesEncrypt(content, KEY); - System.out.println("after encrypt:" + encrypt); - String decrypt = aesDecrypt(encrypt); - System.out.println("after decrypt:" + decrypt); - } - -} \ No newline at end of file diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/util/AESEncryptionUtilTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/util/AESEncryptionUtilTest.java index 1a45b42ea..3af026c7a 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/util/AESEncryptionUtilTest.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/util/AESEncryptionUtilTest.java @@ -1,6 +1,6 @@ package com.tencent.supersonic.util; -import com.tencent.supersonic.auth.authentication.utils.AESEncryptionUtil; +import com.tencent.supersonic.common.util.AESEncryptionUtil; public class AESEncryptionUtilTest { @@ -31,5 +31,19 @@ public class AESEncryptionUtilTest { String password2 = AESEncryptionUtil.encrypt("zhangsan1234", decodeSalt); System.out.println("password2: " + password2); + String content = "123"; + System.out.println("before AES/CBC encrypt:" + content); + String encrypt = AESEncryptionUtil.aesEncryptCBC(content); + System.out.println("after AES/CBC encrypt:" + encrypt); + String decrypt = AESEncryptionUtil.aesDecryptCBC(encrypt); + System.out.println("after AES/CBC decrypt:" + decrypt); + + String str = "123"; + System.out.println("before AES/ECB encrypt:" + str); + String encryptStr = AESEncryptionUtil.aesEncryptECB(str); + System.out.println("after AES/ECB encrypt:" + encryptStr); + String decryptStr = AESEncryptionUtil.aesDecryptECB(encryptStr); + System.out.println("after AES/ECB decrypt:" + decryptStr); + } }