概述
高階加密標準(AES,Advanced Encryption Standard)為最常見的對稱加密演算法,對稱加密演算法即加密和解密的過程使用同一個秘鑰進行加密。本文從實用的角度去描述前後端使用AES對稱加密。
需求分析前端請求資料傳遞引數時,需要對其進行加密,而不是使用明文進行傳輸,防止http請求被人截獲而獲取到資訊,AES對稱加密就是一種方式,前端對密碼進行加密,傳輸給後端,後端獲取之後使用和前端約定好的秘鑰進行解密。
前端AES加解密前端加密需要引入crypto-js的js檔案,crypto-js是加密標準的JavaScript庫,實現了各種加密演算法,下載地址:https://www.yuque.com/docs/share/a764ecd9-3f47-4d40-8ec6-b80aca710d38?# 《前後端加密crypto-js.js檔案》
實操,demo如下前端AES加解密程式碼:
// 金鑰var key = '38373134313330303030333134313738'; key = CryptoJS.enc.Hex.parse(key) var iv = CryptoJS.enc.Hex.parse("303132333435233454243444546") var src = mobile_phone; console.log('原字串:', src); var enc = CryptoJS.AES.encrypt(src ,key,{ iv:iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }) console.log('加密:',enc.toString()); var enced = enc.ciphertext.toString() console.log("加密:", enced); var dec = CryptoJS.AES.decrypt(CryptoJS.format.Hex.parse(enced), key,{ iv:iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }) console.log('解密:',CryptoJS.enc.Utf8.stringify(dec));
其中key和iv的值並不是隨意填寫的,這個是需要後端加解密生成後給到前端使用
後端AES加解密:
package unis.cloud.data.tool;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 AesTool { private static String iv = "0123456789ABCDEF";//偏移量字串必須是16位 當模式是CBC的時候必須設定偏移量 private static String Algorithm = "AES"; private static String AlgorithmProvider = "AES/CBC/PKCS5Padding"; //演算法/模式/補碼方式 public static byte[] generatorKey() throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(Algorithm); keyGenerator.init(256);//預設128,獲得無政策許可權後可為192或256 SecretKey secretKey = keyGenerator.generateKey(); return secretKey.getEncoded(); } public static IvParameterSpec getIv() throws UnsupportedEncodingException { IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8")); System.out.println("偏移量:"+byteToHexString(ivParameterSpec.getIV())); return ivParameterSpec; } public static byte[] encrypt(String src) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException { byte key[] = "87000078".getBytes("utf-8"); 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) throws Exception { byte key[] = "87000078".getBytes("utf-8"); 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; } /** * 將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) "0123456789ABCDEF".indexOf(c); } public static void main(String[] args) { try { // 金鑰必須是16的倍數 byte key[] = "8711110000222278".getBytes("utf-8"); String src = "183222222222"; System.out.println("金鑰:"+byteToHexString(key)); System.out.println("原字串:"+src); String enc = byteToHexString(encrypt(src)); System.out.println("加密:"+enc); System.out.println("解密:"+new String(decrypt(enc), "utf-8")); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }
後端輸出結果:
金鑰:38373134313330303030333134313738原字串:你好偏移量:30313233343536373839414243444546加密:08e56adf28a16558631aa0914d04bd0c偏移量:30313233343536373839414243444546解密:你好
需要注意,後端輸出的金鑰和偏移量都要給前端,這樣解析出來的引數才是一致的,其中後端打印出的金鑰對應前端的key,後端打印出的便宜量對應前端的iv中的值!