RSA加密演算法是目前最具影響力的公鑰加密演算法,它能夠抵抗到目前為止已知的絕大多數密碼攻擊。
那關於RSA加密演算法有哪些應用呢?以下舉一個資料庫身份驗證的案例。
在使用資料集進行身份認證時,密碼存在資料庫中,認證時使用者輸入的密碼與資料庫中密碼相同則認證通過,若資料庫被破解了則對系統造成威脅,怎麼保證系統安全呢?這裡就可以應用RSA加密演算法,對權限加密。
思路:
就是在url中傳用戶名密碼時,先把用戶名進行翻轉,然後再進行加密,如輸入的密碼為12,實際後台進行加密的值為21,再與資料庫進行驗證,這樣就可以避免資料庫被破解查看到的是21的加密碼,登陸系統時以21是無法登陸成功的。
以報表軟體FineReport為例,這是一個能讀取各類資料庫的報表軟體,分客戶端和前端展示。
實作方案:
1、把RSA加密使用的第三方套件,放到工程web-inf/lib資料夾下即可。
2、呼叫js檔案
RSA資料夾為前端js加密時需要呼叫js文件,因此需要將Barrett.js、BigInt.js、RSA.js放到工程目錄下如:WebReport/js,新js文件夾放入js檔。
3、定義RSA加密類別
定義RSAUtil.java類文件,先運行類別中generateKeyPair()方法,會在伺服器D盤中產生一個隨機的RSAKey.txt文件,保存公鑰和金鑰,每訪問一次這個方法會刷新一次txt檔。
package com.fr.privilege; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import javax.crypto.Cipher; /** * RSA 工具类。提供加密,解密,生成密钥对等方法。 * 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。 * */ public class RSAUtil { /** * * 生成密钥对 * * * @return KeyPair * * @throws EncryptException */ public static KeyPair generateKeyPair() throws Exception { try { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider()); final int KEY_SIZE = 1024;// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低 keyPairGen.initialize(KEY_SIZE, new SecureRandom()); KeyPair keyPair = keyPairGen.generateKeyPair(); saveKeyPair(keyPair); return keyPair; } catch (Exception e) { throw new Exception(e.getMessage()); } } public static KeyPair getKeyPair() throws Exception { FileInputStream fis = new FileInputStream("C:/RSAKey.txt"); ObjectInputStream oos = new ObjectInputStream(fis); KeyPair kp = (KeyPair) oos.readObject(); oos.close(); fis.close(); return kp; } public static void saveKeyPair(KeyPair kp) throws Exception { FileOutputStream fos = new FileOutputStream("C:/RSAKey.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); // 生成密钥 oos.writeObject(kp); oos.close(); fos.close(); } /** * * 生成公钥 * * * @param modulus * * @param publicExponent * * @return RSAPublicKey * * @throws Exception */ public static RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) throws Exception { KeyFactory keyFac = null; try { keyFac = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider()); } catch (NoSuchAlgorithmException ex) { throw new Exception(ex.getMessage()); } RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger( modulus), new BigInteger(publicExponent)); try { return (RSAPublicKey) keyFac.generatePublic(pubKeySpec); } catch (InvalidKeySpecException ex) { throw new Exception(ex.getMessage()); } } /** * * 生成私钥 * * * @param modulus * * @param privateExponent * * @return RSAPrivateKey * * @throws Exception */ public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) throws Exception { KeyFactory keyFac = null; try { keyFac = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider()); } catch (NoSuchAlgorithmException ex) { throw new Exception(ex.getMessage()); } RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger( modulus), new BigInteger(privateExponent)); try { return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec); } catch (InvalidKeySpecException ex) { throw new Exception(ex.getMessage()); } } /** * * 加密 * * * @param key * 加密的密钥 * * @param data * 待加密的明文数据 * * @return 加密后的数据 * * @throws Exception */ public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception { try { Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider()); cipher.init(Cipher.ENCRYPT_MODE, pk); int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024 // 加密块大小为127 // byte,加密后为128个byte;因此共有2个加密块,第一个127 // byte第二个为1个byte int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小 int leavedSize = data.length % blockSize; int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize; byte[] raw = new byte[outputSize * blocksSize]; int i = 0; while (data.length - i * blockSize > 0) { if (data.length - i * blockSize > blockSize) cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize); else cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize); // 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到 // ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了 // OutputSize所以只好用dofinal方法。 i++; } return raw; } catch (Exception e) { throw new Exception(e.getMessage()); } } /** * * 解密 * * * @param key * 解密的密钥 * * @param raw * 已经加密的数据 * * @return 解密后的明文 * * @throws Exception */ public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception { try { Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider()); cipher.init(cipher.DECRYPT_MODE, pk); int blockSize = cipher.getBlockSize(); ByteArrayOutputStream bout = new ByteArrayOutputStream(64); int j = 0; while (raw.length - j * blockSize > 0) { bout.write(cipher.doFinal(raw, j * blockSize, blockSize)); j++; } return bout.toByteArray(); } catch (Exception e) { throw new Exception(e.getMessage()); } } /** * * * * * @param args * * @throws Exception */ public static void main(String[] args) throws Exception { RSAPublicKey rsap = (RSAPublicKey) RSAUtil.generateKeyPair() .getPublic(); String test = "hello world"; byte[] en_test = encrypt(getKeyPair().getPublic(), test.getBytes()); System.out.println("123:" + new String(en_test)); byte[] de_test = decrypt(getKeyPair().getPrivate(), en_test); System.out.println(new String(de_test)); } }
4、定義密碼驗證類
定義TestPasswordValidatorRSA.java密碼驗證類
定義一個類,命名為TestPasswordValidatorRSA.java,擴展於AbstractPasswordValidator,重寫其中密碼驗證然後再加密,回傳密碼驗證,具體程式碼如下:
package com.fr.privilege; import com.fr.privilege.providers.dao.AbstractPasswordValidator; public class TestPasswordValidatorRSA extends AbstractPasswordValidator{ //@Override public String encodePassword( String clinetPassword) { try { //对密码进行翻转如输入ab翻转后为ba StringBuffer sb = new StringBuffer(); sb.append(new String(clinetPassword)); String bb = sb.reverse().toString(); //进行加密 byte[] en_test = RSAUtil.encrypt(RSAUtil.getKeyPair().getPublic(),bb.getBytes()); //进行解密,如果数据库里面保存的是加密码,则此处不需要进行解密 byte[] de_test = RSAUtil.decrypt(RSAUtil.getKeyPair().getPrivate(),en_test); //返回加密密码 clinetPassword=new String(de_test); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return clinetPassword; //即获取加密密码再与数据库密码匹配。 } @Override public boolean validatePassword(String arg0, String arg1) { // TODO Auto-generated method stub return false; } }
5、編譯類別檔案
先編譯RSAUtil.java類別檔案在伺服器的D磁碟產生RSAKey.txt文件,再編譯TestPasswordValidatorRSA.java類,把編譯後的class檔案放到專案工程web-inf/classes/com/fr/privilege資料夾。
6、登陸Login.jsp頁面設定
客戶端請求到登入頁面,隨機產生一字串,此隨機字串作為金鑰加密密碼,如下代碼:
<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page import="com.fr.privilege.providers.dao.RSAUtil"%> <%!public String Testmo() { String module = ""; try { java.security.interfaces.RSAPublicKey rsap = (java.security.interfaces.RSAPublicKey) RSAUtil .getKeyPair().getPublic(); module = rsap.getModulus().toString(16); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return module; }%> <%!public String Testem() { String empoent = ""; try { java.security.interfaces.RSAPublicKey rsap = (java.security.interfaces.RSAPublicKey) RSAUtil .getKeyPair().getPublic(); empoent = rsap.getPublicExponent().toString(16); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return empoent; }%> <html> <head> <script type="text/javascript" src="ReportServer?op=emb&resource=finereport.js"></script> <script type="text/javascript" src="js/RSA.js"></script> <script type="text/javascript" src="js/BigInt.js"></script> <script type="text/javascript" src="js/Barrett.js"></script> <script type="text/javascript"> function bodyRSA() { setMaxDigits(130); var a = "<%=Testmo()%>"; var b = "<%=Testem()%>"; key = new RSAKeyPair(b,"",a); } function doSubmit() { bodyRSA(); var username = FR.cjkEncode(document.getElementById("username").value); //获取输入的用户名 var password = FR.cjkEncode(document.getElementById("password").value); //获取输入的参数 $.ajax({ url : "ReportServer?op=auth_login&fr_username=" + username + "&fr_password=" + password, //将用户名和密码发送到报表认证地址op=auth_login data : {__redirect__ : 'false'}, complete : function(res) { var jo = FR.jsonDecode(res.responseText); if(jo.url) { window.location=jo.url+ "&_=" + new Date().getTime(); //认证成功跳转页面,因为ajax不支持重定向所有需要跳转的设置 } else{ alert("用户名密码错误!") //认证失败 } } }) } </script> </head> <body> <p> 请登录 </p> <form name="login" method="POST"> <p> 用户名: <input id="username" type="text" /> </p> <p> 密 码: <input id="password" type="password" /> </p> <input type="button" value="登录" onclick="doSubmit()" /> </form> </body> </html>

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)