AES和RSA前后端加解密
先了解AES和RSA加密算法
AES算法
1、運算速度快,在有反饋模式、無反饋模式的軟硬件中,Rijndael都表現出非常好的性能。
2、對內存的需求非常低,適合于受限環境。
3、Rijndael 是一個分組迭代密碼, 分組長度和密鑰長度設計靈活。
4、AES標準支持可變分組長度,分組長度可設定為32 bit的任意倍數,最小值為128 bit,最大值為256 bit。
5、AES的密鑰長度比DES大, 它也可設定為32 比特的任意倍數,最小值為128bit,最大值為256 bit,所以用窮舉法是不可能破解的。
7、AES算法的設計策略是WTS。WTS 是針對差分分析和線性分析提出的,可對抗差分密碼分析和線性密碼分析。
RSA算法
RSA 公鑰加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者的名字。RSA是目前最有影響力的公鑰加密算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數據加密標準。RSA算法基于一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要對 其乘積進行因式分解卻極其難,因此可以將乘積公開作為加密密鑰。
一般來說有兩種用途:
一、公鑰加密
假設一下,我找了兩個數字,一個是1,一個是2。我喜歡2這個數字,就保留起來,不告訴你們(私鑰),然后我告訴大家,1是我的公鑰。
我有一個文件,不能讓別人看,我就用1加密了。別人找到了這個文件,但是他不知道2就是解密的私鑰啊,所以他解不開,只有我可以用
數字2,就是我的私鑰,來解密。這樣我就可以保護數據了。
我的好朋友x用我的公鑰1加密了字符a,加密后成了b,放在網上。別人偷到了這個文件,但是別人解不開,因為別人不知道2就是我的私鑰,
只有我才能解密,解密后就得到a。這樣,我們就可以傳送加密的數據了。
二、私鑰簽名
如果我用私鑰加密一段數據(當然只有我可以用私鑰加密,因為只有我知道2是我的私鑰),結果所有的人都看到我的內容了,因為他們都知
道我的公鑰是1,那么這種加密有什么用處呢?
但是我的好朋友x說有人冒充我給他發信。怎么辦呢?我把我要發的信,內容是c,用我的私鑰2,加密,加密后的內容是d,發給x,再告訴他
解密看是不是c。他用我的公鑰1解密,發現果然是c。
這個時候,他會想到,能夠用我的公鑰解密的數據,必然是用我的私鑰加的密。只有我知道我得私鑰,因此他就可以確認確實是我發的東西。
這樣我們就能確認發送方身份了。這個過程叫做數字簽名。當然具體的過程要稍微復雜一些。用私鑰來加密數據,用途就是數字簽名。
總結:公鑰和私鑰是成對的,它們互相解密。
公鑰加密,私鑰解密。
私鑰數字簽名,公鑰驗證。
接下來就是一個基于兩種算法的前后端加解密Demo
加解密邏輯并不復雜,所以只寫了一個controller層的代碼
package com.example.rsa_aes_demo03.controller;import java.security.PrivateKey; import java.security.PublicKey; import java.util.HashMap; import java.util.Map;import javax.crypto.SecretKey; import javax.servlet.http.HttpServletRequest;import com.example.rsa_aes_demo03.util.AESUtil; import com.example.rsa_aes_demo03.util.RSAUtil; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;/*** @author LL* @Description:* @date*/ @Controller public class HomeController {@RequestMapping("/")public String index() {return "index";}/*** 獲取公鑰** @return*/@ResponseBody@GetMapping("/getPublicKey")public Map<String, Object> getKey(HttpServletRequest request) throws Exception {Map<String, String> keyMap = RSAUtil.createKeys(1024);String publicKey = keyMap.get("publicKey");String privateKey = keyMap.get("privateKey");Map<String, String> maps = new HashMap<>();maps.put("publickey", publicKey);maps.put("privatekey", privateKey);request.getSession().setAttribute("privateKey", privateKey);// 構建反饋模型Map<String, Object> map = new HashMap<>();map.put("code", 0);map.put("message", "success");map.put("data", maps);return map;}@ResponseBody@PostMapping("/login")public Map<String, Object> login(String content, HttpServletRequest request) throws Exception {String privateKey = request.getSession().getAttribute("privateKey").toString();String newContent = RSAUtil.privateDecrypt(content, RSAUtil.getPrivateKey(privateKey));Map<String, String> maps = new HashMap<>();maps.put("content", "解密后的內容: " + newContent);// 構建反饋模型Map<String, Object> map = new HashMap<>();map.put("code", 0);map.put("message", "success");map.put("data", maps);return map;}@GetMapping("/aesview")public String aesView() {return "aesview";}@ResponseBody@RequestMapping("/getAesKey")public Map<String,Object> aesKey(HttpServletRequest request){String key = "AESD2524fegs2s5g";String iv = "AESD2524fegs2s5g";Map<String, String > maps=new HashMap<>();maps.put("key",key);maps.put("iv",iv);Map<String, Object> map=new HashMap<>();map.put("code",0);map.put("message","success");map.put("data",maps);return map;}@ResponseBody@PostMapping("/aesencode")public String aesEncode(String encryptData, String key, String iv) {// 加密return null;}@ResponseBody@PostMapping("/aes" )public Map<String, Object> aesDncode(String content) {// 解密System.out.println("執行到aes代碼");String keys = "AESD2524fegs2s5g";SecretKey key = AESUtil.stringToSecretKey(keys);String decryptData = AESUtil.aesEcbDecrypt(content, key);Map<String,String> mas = new HashMap<>();mas.put("content",decryptData);// 構建反饋模型Map<String, Object> map = new HashMap<>();map.put("code", 0);map.put("message", "success");map.put("data",mas );return map;} }這里還有個加密沒有寫完,但邏輯都是差不多的。
還需要兩個工具類,
AESUtil
最后的main 方法中 也展示了各個方法的使用。
RSAUtil
package com.example.rsa_aes_demo03.util;import com.fasterxml.jackson.databind.ser.Serializers;import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import java.io.ByteArrayOutputStream; import java.security.*; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.HashMap; import java.util.Map;/*** RSA工具類*/ public class RSAUtil {public static final String CHARSET = "UTF-8";public static final String RSA_ALGORITHM = "RSA";public static Map<String, String> createKeys(int keySize) {//為RSA算法創建一個KeyPairGenerator對象KeyPairGenerator kpg;try {kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);} catch (NoSuchAlgorithmException e) {throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");}//初始化KeyPairGenerator對象,密鑰長度kpg.initialize(keySize);//生成密匙對KeyPair keyPair = kpg.generateKeyPair();//得到公鑰Key publicKey = keyPair.getPublic();Base64.Encoder encoder = Base64.getEncoder();String publicKeyStr = encoder.encodeToString(publicKey.getEncoded());//得到私鑰Key privateKey = keyPair.getPrivate();String privateKeyStr = encoder.encodeToString(privateKey.getEncoded());Map<String, String> keyPairMap = new HashMap<String, String>();keyPairMap.put("publicKey", publicKeyStr);keyPairMap.put("privateKey", privateKeyStr);return keyPairMap;}/*** 公鑰加密** @param data* @param publicKey* @return*/public static String publicEncrypt(String data, RSAPublicKey publicKey) {try {Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);cipher.init(Cipher.ENCRYPT_MODE, publicKey);Base64.Encoder encoder = Base64.getEncoder();return encoder.encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));} catch (Exception e) {throw new RuntimeException("加密字符串[" + data + "]時遇到異常", e);}}private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {int maxBlock = 0;if (opmode == Cipher.DECRYPT_MODE) {maxBlock = keySize / 8;} else {maxBlock = keySize / 8 - 11;}ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] buff;int i = 0;try {while (datas.length > offSet) {if (datas.length - offSet > maxBlock) {buff = cipher.doFinal(datas, offSet, maxBlock);} else {buff = cipher.doFinal(datas, offSet, datas.length - offSet);}out.write(buff, 0, buff.length);i++;offSet = i * maxBlock;}} catch (Exception e) {throw new RuntimeException("加解密閥值為[" + maxBlock + "]的數據時發生異常", e);}byte[] resultDatas = out.toByteArray();try {out.close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return resultDatas;}/*** 私鑰解密** @param data* @param privateKey* @return*/public static String privateDecrypt(String data, RSAPrivateKey privateKey) {try {Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);cipher.init(Cipher.DECRYPT_MODE, privateKey);Base64.Decoder decoder = Base64.getDecoder();return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, decoder.decode(data), privateKey.getModulus().bitLength()), CHARSET);} catch (Exception e) {throw new RuntimeException("解密字符串[" + data + "]時遇到異常", e);}}/*** 得到公鑰** @param publicKey 密鑰字符串(經過base64編碼)* @throws Exception*/public static RSAPublicKey getPublicKey(String publicKey) throws Exception {//通過X509編碼的Key指令獲得公鑰對象KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);Base64.Decoder decoder = Base64.getDecoder();X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decoder.decode(publicKey));RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);return key;}/*** 得到私鑰** @param privateKey 密鑰字符串(經過base64編碼)* @throws Exception*/public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception {//通過PKCS#8編碼的Key指令獲得私鑰對象KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);Base64.Decoder decoder = Base64.getDecoder();PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(decoder.decode(privateKey));RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);return key;}public static void main(String[] args) throws Exception {Map<String, String> keyMap = RSAUtil.createKeys(1024);String publicKey = keyMap.get("publicKey");String privateKey = keyMap.get("privateKey");System.out.println("公鑰: \n\r" + publicKey);System.out.println("私鑰: \n\r" + privateKey);System.out.println("公鑰加密——私鑰解密");String str = "111";System.out.println("\r明文:\r\n" + str);System.out.println("\r明文大小:\r\n" + str.getBytes().length);String encodedData = RSAUtil.publicEncrypt(str, RSAUtil.getPublicKey(publicKey));System.out.println("密文:\r\n" + encodedData);String decodedData = RSAUtil.privateDecrypt(encodedData, RSAUtil.getPrivateKey(privateKey));System.out.println("解密后文字: \r\n" + decodedData);} }有不懂的怎么用的可以參考main方法。
最后就是兩個前端頁面的代碼了。
index.html
aesview.html
<!DOCTYPE html> <html> <head><meta charset="UTF-8"><title>Insert title here</title> </head> <body> <input type="text" id="content"/> <input type="button" value="根據服務端公鑰加密" onclick="login()"> <br> <br> <hr> <label>密文:</label> <div id="cipherText"></div> <label>密鑰:</label> <div id="aeskey"></div> <label>iv:</label> <div id="iv"></div> <label>加密傳輸</label> <div id="encryptContent"></div> <label>解密后</label> <div id="decryptContent"></div> <label>Js解密</label> <div id="decryptContent2"></div> </body> </html> <script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/core.js"></script> <script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/cipher-core.js"></script> <script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/mode-ecb.js"></script> <script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/aes.js"></script> <script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/enc-base64.js"></script> <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <script>// 測試加、解密function testAES() {var key = "8NONwyJtHesysWpM";var plaintText = 'ABCDEFGH'; // 明文var encryptedData = getAesString(plaintText, key);console.log(encryptedData);var encryptedBase64Str = CryptoJS.enc.Base64.stringify(encryptedData.ciphertext);console.log("密文: " + encryptedBase64Str + "");console.log("解密后: " + getDAesString(encryptedData, key));}$(function () {getKey();})function getKey() {$.ajax({url: '/getAesKey',method: 'get',dataType: 'json',success:function (res) {if (res.code == 0){var key=res.data.key;var iv= res.data.iv;$("#aeskey").text(key);$("#iv").text(iv);}}})}function login() {var content = $('#content').val();//前端進行加密var key =$("#aeskey").text();var Encryptcontent = getAesString(content,key);$("#encryptContent").text(Encryptcontent);//前端進行解密var decrypt= getDAesString(Encryptcontent,key);$("#decryptContent2").text(decrypt);dologin(Encryptcontent)}function dologin(content) {$.ajax({url: '/aes',method: 'post',dataType: 'json',data: {content: content},success: function (res) {console.log(res);$("#decryptContent").text(res.data.content)}})}function getAesString(data, key) {//加密var key = CryptoJS.enc.Utf8.parse(key);var encrypted = CryptoJS.AES.encrypt(data, key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted; //返回的是base64格式的密文}function getDAesString(encrypted, key) {//解密var key = CryptoJS.enc.Utf8.parse(key);var decrypted = CryptoJS.AES.decrypt(encrypted, key,{mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return decrypted.toString(CryptoJS.enc.Utf8);} </script>參考博客:https://blog.csdn.net/bruce135lee/article/details/78283806
還有些不記得原地址,在此也感謝大佬們。
總結
以上是生活随笔為你收集整理的AES和RSA前后端加解密的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java opencv4.5 人脸对比_
- 下一篇: 去除VScode中的黄色警告波浪线问题