从零开始构建前后端AES加密通信

推荐

这里推荐使用ECB方式

CBC方式还是有问题,后端没有解密成功

使用方式

前端加密接口参数

后端解密参数,返回正常数据

下包

npm i -S crypto-js

aes的ECB加密方式

新建crypto.js文件,构建crypto类

import CryptoJS from 'crypto-js';
class CryptoFile {
  constructor () {
    // 秘钥
    this.key = CryptoJS.enc.Utf8.parse('CRYPTOJSKEY00000'); // 16位
    this.iv = CryptoJS.enc.Utf8.parse('CRYPTOJSKEY00000');
  }
  // 加密
  encrypt(word) {
    let words = CryptoJS.enc.Utf8.parse(word);
    let encrypted = CryptoJS.AES.encrypt(words, this.key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.toString();
  }
  
  // 解密
  decrypt(word) {
    let decrypt = CryptoJS.AES.decrypt(word, this.key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
  }
}
export default new CryptoFile()

前端使用

引入类

import crypto from './crypto';

在需要的地方使用

我们可以自己测试,看看是不是加密,解密成功

let data = '你加密的数据'
let encryptData = crypto.encrypt(JSON.stringify(data)); // 加密后的数据
let decryptData = crypto.decrypt(encryptData) // 解密后的数据

后端java使用

java不支持Pkcs7,这个需要自己去下jar包设置

package com.CryptPacket;


import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;


/**
 * AES加解密工具
 * AES-128: key和iv都是16个字节,16*8=128bit,java似乎只支持AES-128
 */
public class AESCrypt {
    /**
     * AES ECB 加密
     * @param message 需要加密的字符串
     * @param key   密匙
     * @return  返回加密后密文,编码为base64
     */
    public static String encryptECB(String message, String key) {
        final String cipherMode = "AES/ECB/PKCS5Padding";
        final String charsetName = "UTF-8";
        try {
            byte[] content = new byte[0];
            content = message.getBytes(charsetName);
            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            byte[] data = cipher.doFinal(content);
            final Base64.Encoder encoder = Base64.getEncoder();
            final String result = encoder.encodeToString(data);
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }

        return null;
    }
    /**
     * AES ECB 解密
     * @param messageBase64 密文,base64编码
     * @param key   密匙,和加密时相同
     * @return  解密后数据
     */
    public static String decryptECB(String messageBase64, String key) {
        final String cipherMode = "AES/ECB/PKCS5Padding";
        final String charsetName = "UTF-8";
        try {
            final Base64.Decoder decoder = Base64.getDecoder();
            byte[] messageByte = decoder.decode(messageBase64);

            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] content = cipher.doFinal(messageByte);
            String result = new String(content, charsetName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 测试
     */
    public static void Test()
    {
        String key = "1234567890123456";
        String iv = "1234567890000000";
        String msg = "这是一个测试这是一个测试这是一个测试";
        {
            String encrypt = AESCrypt.encryptCBC(msg, key, iv);
            System.out.println(encrypt);
            String decryptStr = AESCrypt.decryptCBC(encrypt, key, iv);
            System.out.println(decryptStr);
        }
        {
            String encrypt = AESCrypt.encryptECB(msg, key);
            System.out.println(encrypt);
            String decryptStr = AESCrypt.decryptECB(encrypt, key);
            System.out.println(decryptStr);
        }
    }
}

aes的CBC加密方式

前端构建crypto类

import CryptoJS from 'crypto-js';
class CryptoFile {
  constructor () {
    // 秘钥
    this.key = CryptoJS.enc.Utf8.parse('CRYPTOJSKEY00000'); // 16位
    this.iv = CryptoJS.enc.Utf8.parse('CRYPTOJSKEY00000');
  }
  // 加密
  encrypt(word) {
    let words = CryptoJS.enc.Utf8.parse(word);
    let encrypted = CryptoJS.AES.encrypt(words, this.key, { iv: this.iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.ciphertext.toString().toUpperCase();
  }
  
  // 解密
  decrypt(word) {
    let encryptedHexStr = CryptoJS.enc.Hex.parse(word);
    let words = CryptoJS.enc.Base64.stringify(encryptedHexStr);
    let decrypt = CryptoJS.AES.decrypt(words, this.key, { iv: this.iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
  }
}
export default new CryptoFile()

前端使用

引入类

import crypto from './crypto';

在需要的地方使用

我们可以自己测试,看看是不是加密,解密成功

let data = '你加密的数据'
let encryptData = crypto.encrypt(JSON.stringify(data)); // 加密后的数据
let decryptData = crypto.decrypt(encryptData) // 解密后的数据

后端java使用

java不支持Pkcs7,这个需要自己去下jar包或者自己设置

package com.CryptPacket;


import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;


/**
 * AES加解密工具
 * AES-128: key和iv都是16个字节,16*8=128bit,java似乎只支持AES-128
 */
public class AESCrypt {
    /**
     * AES CBC 加密
     * @param message 需要加密的字符串
     * @param key   密匙
     * @param iv    IV,需要和key长度相同
     * @return  返回加密后密文,编码为base64
     */
    public static String encryptCBC(String message, String key, String iv) {
        final String cipherMode = "AES/CBC/PKCS5Padding";
        final String charsetName = "UTF-8";
        try {
            byte[] content = new byte[0];
            content = message.getBytes(charsetName);
            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
            //
            byte[] ivByte = iv.getBytes(charsetName);
            IvParameterSpec ivSpec = new IvParameterSpec(ivByte);

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] data = cipher.doFinal(content);
            final Base64.Encoder encoder = Base64.getEncoder();
            final String result = encoder.encodeToString(data);
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }

        return null;
    }
    /**
     * AES CBC 解密
     * @param messageBase64 密文,base64编码
     * @param key   密匙,和加密时相同
     * @param iv    IV,需要和key长度相同
     * @return  解密后数据
     */
    public static String decryptCBC(String messageBase64, String key, String iv) {
        final String cipherMode = "AES/CBC/PKCS5Padding";
        final String charsetName = "UTF-8";
        try {
            final Base64.Decoder decoder = Base64.getDecoder();
            byte[] messageByte = decoder.decode(messageBase64);

            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
            //
            byte[] ivByte = iv.getBytes(charsetName);
            IvParameterSpec ivSpec = new IvParameterSpec(ivByte);

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] content = cipher.doFinal(messageByte);
            String result = new String(content, charsetName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 测试
     */
    public static void Test()
    {
        String key = "1234567890123456";
        String iv = "1234567890000000";
        String msg = "这是一个测试这是一个测试这是一个测试";
        {
            String encrypt = AESCrypt.encryptCBC(msg, key, iv);
            System.out.println(encrypt);
            String decryptStr = AESCrypt.decryptCBC(encrypt, key, iv);
            System.out.println(decryptStr);
        }
        {
            String encrypt = AESCrypt.encryptECB(msg, key);
            System.out.println(encrypt);
            String decryptStr = AESCrypt.decryptECB(encrypt, key);
            System.out.println(decryptStr);
        }
    }
}

参考资料

AES加解密,js前端和java后端实现

前端加密JS库--CryptoJS 使用指南

强大的前端加密/解密js库crypto-js使用解析

Aes加密和解密 Cryptojs和java

原文地址:https://www.cnblogs.com/WhiteM/p/14068778.html