minglipro 0376ef3a9d
All checks were successful
Gitea Actions Build / Build (push) Successful in 59s
no message
2025-09-09 09:36:48 +08:00

134 lines
4.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2025 mingliqiye
*
* Licensed 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.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AesUtils.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.aes;
import com.mingliqiye.utils.base64.Base64Utils;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtils {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final int GCM_IV_LENGTH = 12;
private static final int GCM_TAG_LENGTH = 16;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
/**
* AES加密方法使用GCM模式
* @param sSrc 待加密的字符串
* @param sKey 加密密钥
* @return 加密后的字符串,格式为 IV:EncryptedData+Tag均为Base64编码
* @throws GeneralSecurityException 加密错误
*/
public static String encrypt(String sSrc, String sKey)
throws GeneralSecurityException {
if (sKey == null) {
return null;
}
// 生成密钥
SecretKeySpec secretKeySpec = createSecretKey(sKey);
// 生成安全随机IV
byte[] iv = new byte[GCM_IV_LENGTH];
SECURE_RANDOM.nextBytes(iv);
// 初始化加密器
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(
GCM_TAG_LENGTH * 8,
iv
);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
// 执行加密
byte[] encrypted = cipher.doFinal(
sSrc.getBytes(StandardCharsets.UTF_8)
);
// 将IV和加密数据包含认证标签组合返回
return Base64Utils.encode(
(Base64Utils.encode(iv) +
":" +
Base64Utils.encode(encrypted)).getBytes()
);
}
/**
* AES解密方法使用GCM模式
* @param sSrc 待解密的字符串,格式为 IV:EncryptedData+Tag均为Base64编码
* @param sKey 解密密钥
* @return 解密后的原始字符串
*/
public static String decrypt(String sSrc, String sKey) {
if (sKey == null) {
return null;
}
try {
// 分割IV和加密数据
String sSrcs = new String(Base64Utils.decode(sSrc));
String[] parts = sSrcs.split(":", 2);
if (parts.length != 2) {
return null;
}
byte[] iv = Base64Utils.decode(parts[0]);
byte[] encryptedData = Base64Utils.decode(parts[1]);
if (iv.length != GCM_IV_LENGTH) {
return null;
}
SecretKeySpec secretKeySpec = createSecretKey(sKey);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(
GCM_TAG_LENGTH * 8,
iv
);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
byte[] original = cipher.doFinal(encryptedData);
return new String(original, StandardCharsets.UTF_8);
} catch (Exception e) {
return null;
}
}
/**
* 创建AES密钥支持任意长度的密钥
* @param sKey 字符串密钥
* @return SecretKeySpec对象
* @throws Exception 可能抛出的异常
*/
private static SecretKeySpec createSecretKey(String sKey)
throws GeneralSecurityException {
byte[] key = sKey.getBytes(StandardCharsets.UTF_8);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(key);
return new SecretKeySpec(digest, ALGORITHM);
}
}