generated from mingliqiye/lib-tem
All checks were successful
Gitea Actions Build / Build (push) Successful in 53s
134 lines
4.0 KiB
Java
134 lines
4.0 KiB
Java
/*
|
||
* 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);
|
||
}
|
||
}
|