AES 加解密 前后台 Java JS

简介

AES是一种对称加密方式,对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。
对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。

加密标准

AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同,如下表所示:

AES 密钥长度(32位比特字) 分组长度(32位比特字) 加密轮数
AES-128 4 4 10
AES-192 6 4 12
AES-256 8 4 14

Java后端实现(128位)

导入依赖:

<!--AES加解密依赖-->
        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>

实现工具类:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class AesUtil {

    //加密时调用方法,三个参数分别是:明文,密钥,向量,注意向量的长度只能是16byte,而且加密解密时必须使用一致的向量。
    public static byte[] AES_CBC_Encrypt(byte[] content, byte[] keyBytes,
            byte[] iv) {

        try {
            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
            // PKCS7Padding是缺几个字节就补几个字节的0,而PKCS5Padding是缺几个字节就补充几个字节的几,好比缺6个字节,就补充6个字节的6 
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            System.out.println("exception:" + e.toString());
        }
        return null;
    }

    //解密方法,三个参数:密文,密钥,向量
    public static byte[] AES_CBC_Decrypt(byte[] content, byte[] keyBytes,
            byte[] iv) {

        try {
            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            System.out.println("exception:" + e.toString());
        }
        return null;
    }

    /**
     *将base64类型的字符串转成byte类型
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception {
        return Base64.decodeBase64(key.getBytes());
    }

    /**
     * 将byte类型转变为base64类型的字符串
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key) throws Exception {
        return new String(Base64.encodeBase64(key));
    }


    /**
     * 字符串转二进制字符串
     * 
     * @param str
     */
    public String toBinary(String str) {

        char[] strChar = str.toCharArray();
        String result = "";
        for (int i = 0; i < strChar.length; i++) {
            result += Integer.toBinaryString(strChar[i]) + "";
        }

        return result;
    }

    /**
     * 字符串转16进制字符串
     * @param s
     * @return
     */
    public static String strTo16(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = (int) s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }


    public static void main(String[] args) throws Exception {

        //明文
        String returnMessageContent = "矛盾综合体";
        // 密钥,一定是16byte长度的 前后台需要一致
        String key = "SHmfaQwNX6nzb3Ee";
        // 向量,一定是16byte长度的 前后台需要一致
        String iv = "SHmfaQwNX6nzb3Ee";
        //注意第一个参数-明文转化为byte数组的时候,一定要指定是按照utf-8的格式进行转化的,不然对中文的加密就会出现加密后无法解密的情况。
        //第三个参数-向量,一定是16byte长度的
        byte[] encrypted = AesUtil.AES_CBC_Encrypt(returnMessageContent.getBytes("utf-8"), key.getBytes(), iv.getBytes());
        //将加密后的密文转成base64格式的字符串
        String secretWord = AesUtil.encryptBASE64(encrypted);
        System.out.println(secretWord);


        String chat_content = secretWord;
        // 解密,获得消息明文
        byte[] chat_contentming = AesUtil.AES_CBC_Decrypt(AesUtil.decryptBASE64(chat_content), key.getBytes(), iv.getBytes());
        //将明文byte按照utf-8的形式转化为String字符串
        String messageming = new String(chat_contentming, "utf-8");
        System.out.println(messageming);

    }

}

运行结果

GilLsEWESwtMFdyJ6P7rpg==
矛盾综合体

前端实现(JS)

导入依赖, 下载地址: https://github.com/sytelus/CryptoJS
依赖js的路径改成你自己的

<!--js AES需要引入的依赖-->
<script type="text/javascript" src="./CryptoJS-master/components/core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/md5.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/evpkdf.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/enc-base64.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/cipher-core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/mode-ecb.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/pad-nopadding.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/aes.js"></script>

html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AES加解密</title>

</head>
<body>

<!--js AES需要引入的依赖-->
<script type="text/javascript" src="./CryptoJS-master/components/core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/md5.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/evpkdf.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/enc-base64.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/cipher-core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/mode-ecb.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/pad-nopadding.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/aes.js"></script>

<script type="text/javascript">

    // 加密方法
    function getAesString(data, key, iv) {

        var key = CryptoJS.enc.Utf8.parse(key);
        var iv = CryptoJS.enc.Utf8.parse(iv);
        var encrypted = CryptoJS.AES.encrypt(data, key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.toString(); // 返回的是base64格式的密文
    }

    // 解密方法
    function getDAesString(encrypted, key, iv) {
        var key = CryptoJS.enc.Utf8.parse(key);
        var iv = CryptoJS.enc.Utf8.parse(iv);
        var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return decrypted.toString(CryptoJS.enc.Utf8); // 返回明文
    }

    // 明文
    var data = "矛盾综合体";
    // 密钥,一定是16byte长度的 前后台需要一致
    var key = 'SHmfaQwNX6nzb3Ee';
    // 向量,一定是16byte长度的 前后台需要一致
    var iv = 'SHmfaQwNX6nzb3Ee';

    // 密文,生成的密文就是base64格式的
    var encrypted = getAesString(data, key, iv);
    console.log(encrypted);

    //生成的decryptedStr已经被默认转为了utf-8类型的字符串
    var decryptedStr = getDAesString(encrypted, key, iv);
    console.log(decryptedStr);

</script>

</body>
</html>

部署运行, 打开浏览器控制台Console, 运行结果

GilLsEWESwtMFdyJ6P7rpg==
矛盾综合体

前后端密文和明文内容一致, 表明没有问题.

实践中遇到的问题

  • JDK自带jar包不支持256位AES加密,需要到官网上下载下面两个jar包替换下面目录中的文件【文件目录:JAVA_HOME/jre/lib/security】:local_policy 和 US_export_policy

  • JAVA中IV【初始化向量不可以为32位,否则异常java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long】

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容