zoukankan      html  css  js  c++  java
  • CryptoJS中AES实现前后端通用加解密

    在项目中如果要对前后端传输的数据双向加密, 比如避免使用明文传输用户名,密码等数据。 就需要对前后端数据用同种方法进行加密,方便解密。这里介绍使用 CryptoJS 实现 AES 加解密。

    首先需要下载前台使用 CryptoJS 实现 AES 加解密的,所以要先下载组件,下载 CryptoJS-v3.1.2 版本之后,文件中包含components 和 rollups 两个文件夹,components 文件夹下是单个组件,rollups 文件夹下是汇总,引用 rollups 下的 aes.js 文件即可。

    已解决解密数据时出现的异常: exception:javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

     这里提供 CryptoJS-v3.1.2 的 Github链接

     先上后台Java代码: 

    package com.company.pms.pmsbase.utils;
     
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
     
    import org.apache.commons.codec.binary.Base64;
     
    public class AesUtil {
     
     public static void main(String args[]) throws Exception {
     
      String content = "明文 123 abc";
     
      //加密
      String encrypted = encrypt(content, KEY, IV);
      //解密
      String decrypted = decrypt(encrypted, KEY, IV);
     
      System.out.println("加密前:" + content);
     
      System.out.println("加密后:" + encrypted);
     
      System.out.println("解密后:" + decrypted);
     }
     
     private static String KEY = "abcdef0123456789"; // 长度必须是 16
     
     private static String IV = "abcdef0123456789"; // 长度必须是 16
     
     /**
      * 加密返回的数据转换成 String 类型
      * @param content 明文
      * @param key 秘钥
      * @param iv 初始化向量是16位长度的字符串
      * @return
      * @throws Exception
      */
     public static String encrypt(String content, String key, String iv) throws Exception {
      // 将返回的加密过的 byte[] 转换成Base64编码字符串 !!!!很关键
      return base64ToString(AES_CBC_Encrypt(content.getBytes(), key.getBytes(), iv.getBytes()));
     }
     
     /**
      * 将解密返回的数据转换成 String 类型
      * @param content Base64编码的密文
      * @param key 秘钥
      * @param iv 初始化向量是16位长度的字符串
      * @return
      * @throws Exception
      */
     public static String decrypt(String content, String key, String iv) throws Exception {
      // stringToBase64() 将 Base64编码的字符串转换成 byte[] !!!与base64ToString()配套使用
      return new String(AES_CBC_Decrypt(stringToBase64(content), key.getBytes(), iv.getBytes()));
     }
     
     private static byte[] AES_CBC_Encrypt(byte[] content, byte[] keyBytes, byte[] iv){
      try {
       SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
       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;
     }
     
     private 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
      */
     
     public static byte[] stringToBase64(String key) throws Exception {
      return Base64.decodeBase64(key.getBytes());
     }
     
     /**
      * Base64装换成字符串
      */
     public static String base64ToString(byte[] key) throws Exception {
      return new Base64().encodeToString(key);
     }
     
    }

    再上前端代码(需引用 rollups 目录下的 aes.js ):

    function encodeAesString(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 
     });
     //返回的是base64格式的密文 
     return encrypted;
    }
     
    // encrypted 为是base64格式的密文
    function decodeAesString(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);
    }
     
    // 测试加、解密
    function testAES(){
     var data = "明文 123 abc"; // 明文 
     var key = 'abcdef0123456789'; // 密钥 长度16
     var iv = 'abcdef0123456789'; // 密钥 长度16
     
     console.log("加密前:" + data);
     
     // 测试加密
     var encrypted = encodeAesString(data,key,iv); // 密文
     console.log("加密后: " + encrypted);
     
     var decryptedStr = decodeAesString(encrypted,key,iv);
     console.log("解密后: " + decryptedStr);
    }

    贴上效果图:

     

    注意:KEY 和  IV 要保持前后端一直才能一样!

    中间遇到的问题: 

        1.  秘钥问题, 秘钥的长度必须为16位, 否则会报错

        2. 加密得到的 byte[] 需用使用Base64转换成字符串, 不能直接转成字符串,因为加密所采用的AES, MD5, SHA-256, SHA-512 等等算法,它们是通过对byte[] 进行各种变换和运算,得到加密之后的byte[],那么这个加密之后的 byte[] 结果显然 就不会符合任何一种的编码方案,比如 UTF-8, GBK等,因为加密的过程是任意对byte[]进行运算的。所以你用任何一种编码方案来解码 加密之后的 byte[] 结果,得到的都会是乱码。

  • 相关阅读:
    各种算法七
    各种算法六
    使用URLConnection调用axis1.4开发的webservice
    JDBC结果集rs.next()注意事项
    URLConnection调用接口
    axis1.4开发webservice客户端(快速入门)-基于jdk1.4
    axis1.4开发webservice服务端(快速入门)-基于jdk1.4
    FMDB数据库的简单实用
    Xcode5 取消项目ARC,或者单个类ARC切换
    用CornerStone配置SVN,HTTP及svn简单使用说明
  • 原文地址:https://www.cnblogs.com/xiejn/p/14037078.html
Copyright © 2011-2022 走看看