在項(xiàng)目中如果要對(duì)前后端傳輸?shù)臄?shù)據(jù)雙向加密, 比如避免使用明文傳輸用戶名,密碼等數(shù)據(jù)。 就需要對(duì)前后端數(shù)據(jù)用同種方法進(jìn)行加密,方便解密。這里介紹使用 CryptoJS 實(shí)現(xiàn) AES 加解密。
創(chuàng)新互聯(lián)憑借專業(yè)的設(shè)計(jì)團(tuán)隊(duì)扎實(shí)的技術(shù)支持、優(yōu)質(zhì)高效的服務(wù)意識(shí)和豐厚的資源優(yōu)勢(shì),提供專業(yè)的網(wǎng)站策劃、網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、網(wǎng)站優(yōu)化、軟件開(kāi)發(fā)、網(wǎng)站改版等服務(wù),在成都10年的網(wǎng)站建設(shè)設(shè)計(jì)經(jīng)驗(yàn),為成都上千多家中小型企業(yè)策劃設(shè)計(jì)了網(wǎng)站。
首先需要下載前臺(tái)使用 CryptoJS 實(shí)現(xiàn) AES 加解密的,所以要先下載組件,下載 CryptoJS-v3.1.2 版本之后,文件中包含components 和 rollups 兩個(gè)文件夾,components 文件夾下是單個(gè)組件,rollups 文件夾下是匯總,引用 rollups 下的 aes.js 文件即可。
已解決解密數(shù)據(jù)時(shí)出現(xiàn)的異常: exception:javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
這里提供 CryptoJS-v3.1.2 的 Github鏈接
先上后臺(tái)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"; // 長(zhǎng)度必須是 16 private static String IV = "abcdef0123456789"; // 長(zhǎng)度必須是 16 /** * 加密返回的數(shù)據(jù)轉(zhuǎn)換成 String 類型 * @param content 明文 * @param key 秘鑰 * @param iv 初始化向量是16位長(zhǎng)度的字符串 * @return * @throws Exception */ public static String encrypt(String content, String key, String iv) throws Exception { // 將返回的加密過(guò)的 byte[] 轉(zhuǎn)換成Base64編碼字符串 !?。。『荜P(guān)鍵 return base64ToString(AES_CBC_Encrypt(content.getBytes(), key.getBytes(), iv.getBytes())); } /** * 將解密返回的數(shù)據(jù)轉(zhuǎn)換成 String 類型 * @param content Base64編碼的密文 * @param key 秘鑰 * @param iv 初始化向量是16位長(zhǎng)度的字符串 * @return * @throws Exception */ public static String decrypt(String content, String key, String iv) throws Exception { // stringToBase64() 將 Base64編碼的字符串轉(zhuǎn)換成 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); } // 測(cè)試加、解密 function testAES(){ var data = "明文 123 abc"; // 明文 var key = 'abcdef0123456789'; // 密鑰 長(zhǎng)度16 var iv = 'abcdef0123456789'; // 密鑰 長(zhǎng)度16 console.log("加密前:" + data); // 測(cè)試加密 var encrypted = encodeAesString(data,key,iv); // 密文 console.log("加密后: " + encrypted); var decryptedStr = decodeAesString(encrypted,key,iv); console.log("解密后: " + decryptedStr); }
貼上效果圖:
中間遇到的問(wèn)題:
1. 秘鑰問(wèn)題, 秘鑰的長(zhǎng)度必須為16位, 否則會(huì)報(bào)錯(cuò)
2. 加密得到的 byte[] 需用使用Base64轉(zhuǎn)換成字符串, 不能直接轉(zhuǎn)成字符串,因?yàn)榧用芩捎玫腁ES, MD5, SHA-256, SHA-512 等等算法,它們是通過(guò)對(duì)byte[] 進(jìn)行各種變換和運(yùn)算,得到加密之后的byte[],那么這個(gè)加密之后的 byte[] 結(jié)果顯然 就不會(huì)符合任何一種的編碼方案,比如 UTF-8, GBK等,因?yàn)榧用艿倪^(guò)程是任意對(duì)byte[]進(jìn)行運(yùn)算的。所以你用任何一種編碼方案來(lái)解碼 加密之后的 byte[] 結(jié)果,得到的都會(huì)是亂碼。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。