🔑 密钥生成
当前密钥: 点击上方按钮生成密钥
🔒 数据加密
加密结果将显示在这里...
🔓 数据解密
解密结果将显示在这里...
🔄 完整流程演示
加密过程
等待演示...
解密过程
等待演示...
🛠️ 工具函数
转换结果将显示在这里...
基于Web Crypto API的AES-CBC加密解密工具
/**
* AES加密工具类 (JavaScript版本)
*/
class AESUtil {
// 字符编码
static CHAR_ENCODING = 'UTF-8';
// AES算法常量
static AES_ALGORITHM = 'AES';
// 十六进制字符数组
static HEXCHAR = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
/**
* 随机生成 AESKey密钥
* @param {number} length 随机生成密钥长度
* @returns {string} 生成的密钥
*/
static getAESKey(length) {
let ret = '';
for (let i = 0; i < length; i++) {
const isChar = (Math.floor(Math.random() * 2) % 2 === 0);
if (isChar) {
const choice = (Math.floor(Math.random() * 2) % 2 === 0) ? 65 : 97;
ret += String.fromCharCode(choice + Math.floor(Math.random() * 26));
} else {
ret += Math.floor(Math.random() * 10);
}
}
return ret;
}
/**
* 加密
* @param {Uint8Array|string} data 待加密数据内容
* @param {Uint8Array|string} aesKey 加密密钥
* @returns {Promise} 加密后的数据
*/
static async encrypt(data, aesKey) {
const keyBytes = typeof aesKey === 'string' ? new TextEncoder().encode(aesKey) : aesKey;
if (keyBytes.length !== 16) {
throw new Error('Invalid AES key length (must be 16 bytes) !');
}
try {
const dataBytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
// 导入密钥为CryptoKey对象
const cryptoKey = await window.crypto.subtle.importKey(
'raw',
keyBytes,
{
name: 'AES-CBC',
length: 128
},
false,
['encrypt']
);
return window.crypto.subtle.encrypt(
{
name: 'AES-CBC',
iv: new Uint8Array(16)
},
cryptoKey,
dataBytes
).then(encrypted => {
return new Uint8Array(encrypted);
});
} catch (e) {
throw new Error('Encrypt fail! ' + e.message);
}
}
/**
* 解密
* @param {Uint8Array} data 解密数据
* @param {Uint8Array|string} aesKey 解密密钥
* @returns {Promise} 解密后的数据
*/
static async decrypt(data, aesKey) {
const keyBytes = typeof aesKey === 'string' ? new TextEncoder().encode(aesKey) : aesKey;
if (keyBytes.length !== 16) {
throw new Error('Invalid AES Key length (must be 16 bytes)');
}
try {
// 导入密钥为CryptoKey对象
const cryptoKey = await window.crypto.subtle.importKey(
'raw',
keyBytes,
{
name: 'AES-CBC',
length: 128
},
false,
['decrypt']
);
return window.crypto.subtle.decrypt(
{
name: 'AES-CBC',
iv: new Uint8Array(16)
},
cryptoKey,
data
).then(decrypted => {
return new Uint8Array(decrypted);
});
} catch (e) {
throw new Error('Decrypt Fail ! ' + e.message);
}
}
/**
* 加密数据,并转换为Base64编码格式
* @param {string} data 待加密数据
* @param {string} aesKey 加密密钥
* @returns {Promise} Base64编码的加密数据
*/
static async encryptToBase64(data, aesKey) {
try {
const valueByte = await this.encrypt(data, aesKey);
return btoa(String.fromCharCode(...valueByte));
} catch (e) {
throw new Error('Encrypt Fail ! ' + e.message);
}
}
/**
* 解密数据,将Base64格式的加密数据进行解密操作
* @param {string} data Base64编码的加密数据
* @param {string} aesKey 解密密钥
* @returns {Promise} 解密后的数据
*/
static async decryptFromBase64(data, aesKey) {
try {
const originalData = Uint8Array.from(atob(data), c => c.charCodeAt(0));
const valueByte = await this.decrypt(originalData, aesKey);
return new TextDecoder().decode(valueByte);
} catch (e) {
throw new Error('Decrypt Fail ! ' + e.message);
}
}
/**
* 加密数据,aesKey为Base64格式时,并将加密后的数据转换为Base64编码格式
* @param {string} data 待加密数据
* @param {string} aesKey Base64编码的密钥
* @returns {Promise} Base64编码的加密数据
*/
static async encryptWithKeyBase64(data, aesKey) {
try {
const keyBytes = Uint8Array.from(atob(aesKey), c => c.charCodeAt(0));
const valueByte = await this.encrypt(data, keyBytes);
return btoa(String.fromCharCode(...valueByte));
} catch (e) {
throw new Error('Encrypt Fail! ' + e.message);
}
}
/**
* 解密数据,数据源为Base64格式,且 aesKey为Base64编码格式
* @param {string} data Base64编码的加密数据
* @param {string} aesKey Base64编码的密钥
* @returns {Promise} 解密后的数据
*/
static async decryptWithKeyBase64(data, aesKey) {
try {
const originalData = Uint8Array.from(atob(data), c => c.charCodeAt(0));
const keyBytes = Uint8Array.from(atob(aesKey), c => c.charCodeAt(0));
const valueByte = await this.decrypt(originalData, keyBytes);
return new TextDecoder().decode(valueByte);
} catch (e) {
throw new Error('Decrypt Fail ! ' + e.message);
}
}
/**
* 通过密钥生成器生成一个随机的 AES 密钥,并将其以字节数组的形式返回
* @returns {Uint8Array} 随机生成的AES密钥字节数组
*/
static generateRandomAesKey() {
try {
const key = window.crypto.getRandomValues(new Uint8Array(16));
return key;
} catch (e) {
throw new Error('GenerateRandomKey Fail !' + e.message);
}
}
/**
* 通过密钥生成器生成一个随机的 AES 密钥,并转化为Base64格式
* @returns {string} Base64编码的随机AES密钥
*/
static generateRandomAesKeyWithBase64() {
const key = this.generateRandomAesKey();
return btoa(String.fromCharCode(...key));
}
/**
* 从Byte[] 数组转 16进制字符串
* @param {Uint8Array} b 字节数组
* @returns {string} 十六进制字符串
*/
static toHexString(b) {
let sb = '';
for (let i = 0; i < b.length; i++) {
sb += this.HEXCHAR[(b[i] & 0xf0) >>> 4];
sb += this.HEXCHAR[b[i] & 0x0f];
}
return sb;
}
/**
* 从16进制字符串转 byte[] 数组
* @param {string} s 十六进制字符串
* @returns {Uint8Array} 字节数组
*/
static toBytes(s) {
const bytes = new Uint8Array(s.length / 2);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(s.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
}
// 导出类
export default AESUtil;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
/**
* AES加密工具类 (Java版本)
* @Author : aber
*/
public class AESUtil {
// 字符编码
private static final String CHAR_ENCODING = "UTF-8";
// AES算法常量
private static final String AES_ALGORITHM = "AES";
// 十六进制字符数组
private static final char[] HEXCHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 随机生成 AESKey密钥
* @param length 随机生成密钥长度
* @return 生成的密钥
*/
public static String getAESKey(int length) {
StringBuilder ret = new StringBuilder();
SecureRandom random = new SecureRandom();
for (int i = 0; i < length; i++) {
boolean isChar = random.nextInt(2) % 2 == 0;
if (isChar) {
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
ret.append((char) (choice + random.nextInt(26)));
} else {
ret.append(random.nextInt(10));
}
}
return ret.toString();
}
/**
* 加密
* @param data 待加密数据内容
* @param aesKey 加密密钥
* @return 加密后的数据
* @throws Exception 加密异常
*/
public static byte[] encrypt(byte[] data, byte[] aesKey) throws Exception {
if (aesKey.length != 16) {
throw new IllegalArgumentException("Invalid AES key length (must be 16 bytes) !");
}
try {
SecretKeySpec secretKey = new SecretKeySpec(aesKey, AES_ALGORITHM);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 使用全零的IV
byte[] iv = new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
return cipher.doFinal(data);
} catch (Exception e) {
throw new Exception("Encrypt fail! " + e.getMessage(), e);
}
}
/**
* 加密字符串
* @param data 待加密字符串
* @param aesKey 加密密钥
* @return 加密后的数据
* @throws Exception 加密异常
*/
public static byte[] encrypt(String data, String aesKey) throws Exception {
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
byte[] keyBytes = aesKey.getBytes(StandardCharsets.UTF_8);
return encrypt(dataBytes, keyBytes);
}
/**
* 解密
* @param data 解密数据
* @param aesKey 解密密钥
* @return 解密后的数据
* @throws Exception 解密异常
*/
public static byte[] decrypt(byte[] data, byte[] aesKey) throws Exception {
if (aesKey.length != 16) {
throw new IllegalArgumentException("Invalid AES Key length (must be 16 bytes)");
}
try {
SecretKeySpec secretKey = new SecretKeySpec(aesKey, AES_ALGORITHM);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 使用全零的IV
byte[] iv = new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
return cipher.doFinal(data);
} catch (Exception e) {
throw new Exception("Decrypt Fail ! " + e.getMessage(), e);
}
}
/**
* 解密为字符串
* @param data 解密数据
* @param aesKey 解密密钥
* @return 解密后的字符串
* @throws Exception 解密异常
*/
public static String decryptToString(byte[] data, String aesKey) throws Exception {
byte[] keyBytes = aesKey.getBytes(StandardCharsets.UTF_8);
byte[] decryptedBytes = decrypt(data, keyBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
/**
* 加密数据,并转换为Base64编码格式
* @param data 待加密数据
* @param aesKey 加密密钥
* @return Base64编码的加密数据
* @throws Exception 加密异常
*/
public static String encryptToBase64(String data, String aesKey) throws Exception {
try {
byte[] valueByte = encrypt(data, aesKey);
return Base64.getEncoder().encodeToString(valueByte);
} catch (Exception e) {
throw new Exception("Encrypt Fail ! " + e.getMessage(), e);
}
}
/**
* 解密数据,将Base64格式的加密数据进行解密操作
* @param data Base64编码的加密数据
* @param aesKey 解密密钥
* @return 解密后的数据
* @throws Exception 解密异常
*/
public static String decryptFromBase64(String data, String aesKey) throws Exception {
try {
byte[] originalData = Base64.getDecoder().decode(data);
byte[] keyBytes = aesKey.getBytes(StandardCharsets.UTF_8);
byte[] valueByte = decrypt(originalData, keyBytes);
return new String(valueByte, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new Exception("Decrypt Fail ! " + e.getMessage(), e);
}
}
/**
* 加密数据,aesKey为Base64格式时,并将加密后的数据转换为Base64编码格式
* @param data 待加密数据
* @param aesKey Base64编码的密钥
* @return Base64编码的加密数据
* @throws Exception 加密异常
*/
public static String encryptWithKeyBase64(String data, String aesKey) throws Exception {
try {
byte[] keyBytes = Base64.getDecoder().decode(aesKey);
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
byte[] valueByte = encrypt(dataBytes, keyBytes);
return Base64.getEncoder().encodeToString(valueByte);
} catch (Exception e) {
throw new Exception("Encrypt Fail! " + e.getMessage(), e);
}
}
/**
* 解密数据,数据源为Base64格式,且 aesKey为Base64编码格式
* @param data Base64编码的加密数据
* @param aesKey Base64编码的密钥
* @return 解密后的数据
* @throws Exception 解密异常
*/
public static String decryptWithKeyBase64(String data, String aesKey) throws Exception {
try {
byte[] originalData = Base64.getDecoder().decode(data);
byte[] keyBytes = Base64.getDecoder().decode(aesKey);
byte[] valueByte = decrypt(originalData, keyBytes);
return new String(valueByte, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new Exception("Decrypt Fail ! " + e.getMessage(), e);
}
}
/**
* 通过密钥生成器生成一个随机的 AES 密钥,并将其以字节数组的形式返回
* @return 随机生成的AES密钥字节数组
* @throws Exception 生成密钥异常
*/
public static byte[] generateRandomAesKey() throws Exception {
try {
KeyGenerator keyGen = KeyGenerator.getInstance(AES_ALGORITHM);
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
return secretKey.getEncoded();
} catch (Exception e) {
throw new Exception("GenerateRandomKey Fail !" + e.getMessage(), e);
}
}
/**
* 通过密钥生成器生成一个随机的 AES 密钥,并转化为Base64格式
* @return Base64编码的随机AES密钥
* @throws Exception 生成密钥异常
*/
public static String generateRandomAesKeyWithBase64() throws Exception {
byte[] key = generateRandomAesKey();
return Base64.getEncoder().encodeToString(key);
}
/**
* 从Byte[] 数组转 16进制字符串
* @param b 字节数组
* @return 十六进制字符串
*/
public static String toHexString(byte[] b) {
StringBuilder sb = new StringBuilder();
for (byte value : b) {
sb.append(HEXCHAR[(value & 0xf0) >>> 4]);
sb.append(HEXCHAR[value & 0x0f]);
}
return sb.toString();
}
/**
* 从16进制字符串转 byte[] 数组
* @param s 十六进制字符串
* @return 字节数组
*/
public static byte[] toBytes(String s) {
byte[] bytes = new byte[s.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
}