# Java 和 js 互加解密(1) — AES对称加密算法

本文整理了 Java 和 js 关于AES算法的互加解密,方便开发使用。部分代码来源于网络。

js 前台加密数据,Java 后台解密数据。

Java 和 js 互加解密 — AES对称加密

Java 和 js 互加解密 — AES对称加密

# AES算法简介

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密 (opens new window)中最流行的算法之一。

更多信息请查阅维基词条:高级加密标准 (opens new window)

# Java实现AES加解密

该工具类基于 jdk1.8 进行封装,如果你的 jdk 低于1.8,部分代码可能需要做一定的调整(如Base64编码解码)

import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加解密的工具类
 *
 * @author hxulin
 */
public final class AESUtils {

    /**
     * 字符编码
     */
    private static final String CHARACTER_ENCODING = "utf-8";

    /**
     * 生成密钥的基本字符
     */
    private static final String BASE_CHARACTER = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private AESUtils() {

    }

    /**
     * 生成随机密钥
     *
     * @return 随机密钥
     */
    public static String initKey() {
        return generateKeyOrIV();
    }

    /**
     * 生成初始向量
     *
     * @return 初始向量
     */
    public static String initIV() {
        return generateKeyOrIV();
    }

    /**
     * 生成随机密钥、初始向量
     */
    private static String generateKeyOrIV() {
        StringBuilder sBuilder = new StringBuilder();
        double r;
        for (int i = 0; i < 16; i++) {
            r = Math.random() * BASE_CHARACTER.length();
            sBuilder.append(BASE_CHARACTER.charAt((int) r));
        }
        return sBuilder.toString();
    }

    /**
     * 使用AES算法加密字符串
     *
     * @param data 需要加密的原文
     * @param key  密钥(16位字母、数字或符号)
     * @param iv   初始向量(16位字母、数字或符号),使用CBC模式,需要一个向量iv,可增加加密算法的强度
     * @return 加密后进行Base64的密文
     * @throws Exception 加密失败
     */
    public static String encrypt(String data, String key, String iv) throws Exception {
        return Base64.getEncoder().encodeToString(encrypt(data.getBytes(CHARACTER_ENCODING), key, iv));
    }

    /**
     * 使用AES算法加密数据
     *
     * @param data 需要加密的数据
     * @param key  密钥(16位字母、数字或符号)
     * @param iv   初始向量(16位字母、数字或符号),使用CBC模式,需要一个向量iv,可增加加密算法的强度
     * @return 加密后的数据
     * @throws Exception 加密失败
     */
    public static byte[] encrypt(byte[] data, String key, String iv) throws Exception {
        return crypto(Cipher.ENCRYPT_MODE, data, key, iv);
    }

    /**
     * 使用AES算法解密字符串
     *
     * @param data 需要解密的密文
     * @param key  密钥(16位字母、数字或符号)
     * @param iv   初始向量(16位字母、数字或符号)
     * @return 解密后的明文
     * @throws Exception 解密失败
     */
    public static String decrypt(String data, String key, String iv) throws Exception {
        byte[] decrypted = decrypt(Base64.getDecoder().decode(data), key, iv);
        return new String(decrypted, CHARACTER_ENCODING);
    }

    /**
     * 使用AES算法解密数据
     *
     * @param data 需要解密的数据
     * @param key  密钥(16位字母、数字或符号)
     * @param iv   初始向量(16位字母、数字或符号)
     * @return 解密后的数据
     * @throws Exception 解密失败
     */
    public static byte[] decrypt(byte[] data, String key, String iv) throws Exception {
        return crypto(Cipher.DECRYPT_MODE, data, key, iv);
    }

    /**
     * 加解密数据
     */
    private static byte[] crypto(int opmode, byte[] content, String key, String iv) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARACTER_ENCODING), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");  // 算法/模式/补码方式
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(CHARACTER_ENCODING));
        cipher.init(opmode, keySpec, ivParameterSpec);
        return cipher.doFinal(content);
    }

}

使用样例:

@Test
public void test() throws Exception {
    String key = AESUtils.initKey();
    System.out.println("生成密钥:" + key);
    String iv = AESUtils.initIV();
    System.out.println("生成初始向量:" + iv);
    String content = "你好师姐";  // 待加密内容
    String encrypt = AESUtils.encrypt(content, key, iv);
    System.out.println("明文内容:"+ content);
    System.out.println("加密结果:"+ encrypt);
    System.out.println("解密结果:"+ AESUtils.decrypt(encrypt, key, iv));
}

运行结果:

生成密钥:grXBjElVVSJd4QSq

生成初始向量:DmuZulkW1x240brw

明文内容:你好师姐

加密结果:BqbUwVOXJMwwtB4CquWsLA==

解密结果:你好师姐

# js实现AES加解密

前端 js 实现AES加解密,依赖第三方库:CryptoJS (opens new window)

/**
 * AES加密
 *
 * @param content 待加密的内容
 * @param secretKey 密钥
 * @param iv 初始向量
 * @returns {string} 加密结果
 */
function aesEncrypt(content, secretKey, iv) {
    return CryptoJS.AES.encrypt(content, CryptoJS.enc.Utf8.parse(secretKey), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString();
}

/**
 * AES解密
 *
 * @param content 待解密的内容
 * @param secretKey 密钥
 * @param iv 初始向量
 * @returns {string} 解密结果
 */
function aesDecrypt(content, secretKey, iv) {
    return CryptoJS.AES.decrypt(content, CryptoJS.enc.Utf8.parse(secretKey), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8);
}

完整项目地址:https://github.com/hxulin/encryption (opens new window)

(完)