Der RSA-Verschlüsselungsalgorithmus ist derzeit der einflussreichste Public-Key-Verschlüsselungsalgorithmus und kann der überwiegenden Mehrheit der bisher bekannten kryptografischen Angriffe widerstehen.
Welche Anwendungen bietet der RSA-Verschlüsselungsalgorithmus? Im Folgenden finden Sie ein Beispiel für die Datenbankauthentifizierung.
Bei Verwendung des Datensatzes zur Identitätsauthentifizierung wird das Passwort in der Datenbank gespeichert. Wenn das vom Benutzer bei der Authentifizierung eingegebene Passwort mit dem Passwort in der Datenbank übereinstimmt, wird die Authentifizierung bestanden Ist es geknackt, stellt es eine Gefahr für das System dar. Wie kann die Systemsicherheit gewährleistet werden? Hier können Sie den RSA-Verschlüsselungsalgorithmus anwenden, um Berechtigungen zu verschlüsseln.
Idee:
Wenn Sie den Benutzernamen und das Passwort in der URL übergeben, kehren Sie zuerst den Benutzernamen um und verschlüsseln ihn dann. Wenn das eingegebene Passwort beispielsweise 12 ist, wird der tatsächliche Wert im Hintergrund verschlüsselt ist 21, und überprüfen Sie es dann mit der Datenbank, um zu verhindern, dass die Datenbank geknackt wird und der Verschlüsselungscode von 21 angezeigt wird. Wenn Sie sich beim System anmelden, können Sie sich mit 21 nicht erfolgreich anmelden.
Nehmen Sie als Beispiel die Reporting-Software FineReport. Hierbei handelt es sich um eine Reporting-Software, die verschiedene Datenbanken auslesen kann und in Client- und Frontend-Anzeige unterteilt ist.
Implementierungsplan:
1. Platzieren Sie das für die RSA-Verschlüsselung verwendete Drittanbieterpaket im Ordner web-inf/lib des Projekts.
2. Rufen Sie die js-Datei auf
Wenn der RSA-Ordner für die Front-End-js verschlüsselt ist, muss die js-Datei aufgerufen werden, also Barrett.js, BigInt.js und RSA .js muss wie folgt im Projektverzeichnis abgelegt werden: WebReport/js, erstellen Sie einen neuen js-Ordner und legen Sie die js-Datei darin ab.
3. Definieren Sie die RSA-Verschlüsselungsklasse.
Definieren Sie zunächst die Methode „generateKeyPair()“ in der Klasse Laufwerk D und gespeicherter öffentlicher Schlüssel und geheimer Schlüssel. Diese Methode aktualisiert die TXT-Datei bei jedem Zugriff.
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. Definieren Sie die Passwortüberprüfungsklasse
Definieren Sie die Passwortüberprüfungsklasse TestPasswordValidatorRSA.java
Definieren Sie eine Klasse mit dem Namen TestPasswordValidatorRSA.java, erweitern Sie sie von AbstractPasswordValidator und Umschreiben Unter anderem dreht die Methode zur Passwortüberprüfung encodePassword das eingegebene Passwort um, verschlüsselt es und gibt das Passwort zur Überprüfung zurück. Der spezifische Code lautet wie folgt:
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 >
Zuerst kompilieren Die RSAUtil.java-Klassendatei generiert die RSAKey.txt-Datei auf dem Laufwerk D des Servers, kompiliert dann die TestPasswordValidatorRSA.java-Klasse und fügt die kompilierte Klassendatei in das Projektprojekt web-inf/classes/com/ ein. fr/privilege-Ordner. 6. Login.jsp-Seiteneinstellungen Der Client fordert die Anmeldeseite an und generiert zufällig eine Zeichenfolge, die wie folgt als Schlüsselverschlüsselungskennwort verwendet wird:<%@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>