對稱加解密算法AES+加解密模式CBC+填充模式PKCS5

目錄

參考文本

前言

AES簡介

前端代碼

後臺代碼

後臺加密解密工具類代碼

後臺接收參數接口代碼


參考文本

前端參考:

https://blog.csdn.net/z834410038/article/details/70231668

後端參考:

https://blog.csdn.net/aigoV/article/details/90374838

https://blog.csdn.net/huangxiaoguo1/article/details/78043169

前言

前段時間項目經常被攻擊,有一種是請求被抓包並且修改了請求參數,爲了解決這種問題,決定對請求參數進行加密,加密採用AES的CBC模式。對於加密之前沒大接觸過,AES的CBC模式是什麼鬼?趕緊百度。下面是對AES加密的一點理解,直接複製來的。

AES簡介

1、AES(Advanced Encryption Standard 高級加密標準)算法:

這是一種對稱加密算法,強迫症一定要知道清楚啥對稱加密,對稱加密的意思是指,加密者和解密者用的是同一串祕鑰。

2、128位加解密

這是在約定祕鑰的長度,128位即128bit,AES的祕鑰長度一般有:128bit、192bit、256bit。java 中,祕鑰裏的一個字符是一個字節(1byte),1byte=8bit。一個128位的祕鑰,即由16個字符組成,如:"aigov1266aba186k".

3、加解密模式CBC

AES有四種加解密模式:CBC、EBC、CFB、OFB ,我這次被要求用CBC模式,所以大概瞭解一下CBC。其他幾個,咱也不懂,咱也不敢說。CBC模式下,加密時,是對明文進行分組加密的,每組大小一致,到最後一組時,可能長度不夠,這個時候就需要填充到一樣長度,就有了下面的填充模式。

4、填充模式

有兩種填充模式:PKCS5Padding、PKCS7Padding 。這兩種填充模式填充規則一樣,區別在於,分組時,每組約定大小不一樣。PKCS5Padding要求塊(block)的大小是8位,PKCS7Padding則沒有明確,範圍在1-255之間。

5、Base64編碼

Base64編碼就是將數據編碼成只用大小寫字母,0-9數字,以及符號 + /等64個字符的String字符串,一般我們在網絡中傳輸較長的數據時,會選中這種編碼方式。

明文在經過加密後後變成一個無規則的二進制(二進制文件)byte數組,如:

 ajax無法接收二進制流文件,此時爲了展示和傳輸,我們一般會約定使用Base64編碼進行編碼。將二進制byte數組進行base64編碼後,就得到如下形式字符串:

項目採用的是將流轉換爲16進制的String字符串進行傳遞,直接貼代碼

前端代碼

前端引入crypto-js.js和aes.js

crypto-js.js下載鏈接:https://gitee.com/zhangfanhao/CSDN/blob/master/crypto-js.js

aes.js下載鏈接:https://gitee.com/zhangfanhao/CSDN/blob/master/aes.js

function supper() {

	var miyaokey = '後臺代碼加密解密類中main方法中將祕鑰key轉換爲byte[],再轉換爲16進制的字符串的值';

	miyaokey = CryptoJS.enc.Hex.parse(miyaokey)

	iv = CryptoJS.enc.Hex.parse("後臺代碼加密解密類中main方法中將iv轉換爲byte[],再轉換爲16進制的字符串的值");

	var src = JSON.stringify({
		"accessToken": "",
		"obj": {
			"keyWord":$(".commodity-seek-inp").val(),
			"sortType": "2",//排序方式按佣金高低倒序
			"withCoupon": "true",//只查有優惠劵的
			"isBrandGoods": "false",//只查品牌商品
			"optId":""//商品的分類Id
		},
		"page": page,
		"pageSize": "",
		"msg": ""
	});

	var enc = CryptoJS.AES.encrypt(src, miyaokey, {

		iv: iv,

		mode: CryptoJS.mode.CBC,

		padding: CryptoJS.pad.Pkcs7

	})

	enced = enc.ciphertext.toString();

	$.ajax({

		type: "POST",

		url: "請求地址",

		dataType: "json", //表示返回值類型,不必須

		data: enced,

		success: function(res) {

		},

	});
}

後臺代碼

後臺加密解密工具類代碼

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AES {

    private static String iv = "0123456789ABCDEF";//當模式是CBC的時候必須設置偏移量,偏移量字符串:自己隨意定義,必須是16位 。
    private static String Algorithm = "AES";
    private static String AlgorithmProvider = "AES/CBC/PKCS5Padding"; //算法/模式/補碼方式
	private static String jiaMiKey = "1234567890ABCDEF1234567890ABCDEf"; //加密解密的祕鑰key:自己隨意定義。長度爲n/8。 n代表的是多少bit

    public static IvParameterSpec getIv() throws UnsupportedEncodingException {
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
        return ivParameterSpec;
    }

    public static byte[] encrypt(String src, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);
        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
        return cipherBytes;
    }

    public static byte[] decrypt(String src, byte[] key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);

        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] hexBytes = hexStringToBytes(src);
        byte[] plainBytes = cipher.doFinal(hexBytes);
        return plainBytes;
    }
    public static String toKeyCode(String src) {
        byte key[] = new byte[0];
        String to = null;
        try {
            key = jiaMiKey.getBytes("utf-8");
            to = new String(decrypt(src, key), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return to;
    }

    public static String deKeyCode(String src) {
        byte key[] = new byte[0];
        String to = null;
        try {
            key = jiaMiKey.getBytes("utf-8");
            to = byteToHexString(encrypt(src, key));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return to;
    }


    /**
     * 將byte轉換爲16進制字符串
     * @param src
     * @return
     */
    public static String byteToHexString(byte[] src) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xff;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                sb.append("0");
            }
            sb.append(hv);
        }
        return sb.toString();
    }

    /**
     * 將16進制字符串裝換爲byte數組
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] b = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            b[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return b;
    }
    private static byte charToByte(char c) {
        return (byte) iv.indexOf(c);
    }

    public static void main(String[] args) {
        try {
            byte key[] = jiaMiKey.getBytes("utf-8");
            System.out.println(byteToHexString(key));//給前端的加密key
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        try {
            byte[] vi = iv.getBytes("utf-8");
            System.out.println(byteToHexString(vi));//給前端的iv
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

後臺接收參數接口代碼

@PostMapping("/searchGoods")
public ResultObjVO searchDuoDuoJinBaoGoods(HttpServletRequest req) throws IOException {
	String param = AES.toKeyCode(IOUtils.toString(req.getInputStream(), "UTF-8"));//IOUtils.toString(req.getInputStream(), "UTF-8")返回的是前端傳過來加密的參數。
}

 

發佈了52 篇原創文章 · 獲贊 31 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章