🔐 AES对称加密演示

基于Web Crypto API的AES-CBC加密解密工具

🔑 密钥生成

当前密钥: 点击上方按钮生成密钥

🔒 数据加密

加密结果将显示在这里...

🔓 数据解密

解密结果将显示在这里...

🔄 完整流程演示

加密过程

等待演示...

解密过程

等待演示...

🛠️ 工具函数

转换结果将显示在这里...

📁 代码预览

AESUtil.js

/**
 * 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;

AESUtil.java

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;
    }
}