美文网首页
AES 加解密 前后台 Java JS

AES 加解密 前后台 Java JS

作者: KouKuma | 来源:发表于2020-11-26 10:40 被阅读0次

    简介

    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】

    相关文章

      网友评论

          本文标题:AES 加解密 前后台 Java JS

          本文链接:https://www.haomeiwen.com/subject/cmmniktx.html