accomplish:
Implemented with RSA asymmetric encryption. The rsa key pair is generated in the background, and then the rsa public key is set on the login page. When submitting, the password is encrypted with the public key. The generated ciphertext is sent to the background, decrypted with the private key, and the plaintext of the password is obtained.
In this way, the client only needs to know the RSA encryption method and public key, and the foreground does not know that the private key cannot be decrypted. This solution is relatively safe.
The attachment is the implementation of java+JS with reference to netizens' information, and is here for everyone to download. Access method/RSA/login.jsp.
You need to download the bcprov-jdk14-123.jar file from http://www.bouncycastle.org.
Because the background needs to be converted to bigint, there are some restrictions on the length of the plaintext:
The total length does not exceed 126 (the length of 1 Chinese character is 9), the following two strings:
Ah send Dafa, send Dafa, send Dafa, send
1232132131231231232131232K123213213123123123213131231231232131232K1232132131231231232131232K1234234567891078
RSA speed
* Due to the large number of calculations, the fastest case of RSA is 100 times slower than DES, whether it is implemented in software or hardware.
* Speed has always been a drawback of RSA. Generally only used for small amount of data encryption.
Util.java
package RSA; /** * */ 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 tool class. Provides encryption, decryption, key generation, etc. methods. * You need to download bcprov-jdk14-123.jar from http://www.bouncycastle.org. * */ public class RSAUtil { private static String RSAKeyStore = "C:/RSAKey.txt"; /** * * Generate key pair * * * @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;// There is nothing to say, this value is related to the size of the block encryption and can be changed, but it should not be too large, otherwise the efficiency will be low keyPairGen.initialize(KEY_SIZE, new SecureRandom()); KeyPair keyPair = keyPairGen.generateKeyPair(); System.out.println(keyPair.getPrivate()); System.out.println(keyPair.getPublic()); saveKeyPair(keyPair); return keyPair; } catch (Exception e) { throw new Exception(e.getMessage()); } } public static KeyPair getKeyPair() throws Exception { FileInputStream fis = new FileInputStream(RSAKeyStore); 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(RSAKeyStore); ObjectOutputStream oos = new ObjectOutputStream(fos); // generate key oos.writeObject (kp); oos.close(); fos.close(); } /** * * Generate public key * * * @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()); } } /** * * Generate private key * * * @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()); } } /** * * Encryption * * * @param key *encrypted key* * @param data * Plaintext data to be encrypted * * @return encrypted data * * @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();// Get the encrypted block size, such as: the data before encryption is 128 bytes, and key_size=1024 // encrypted block size is 127 //byte, encrypted is 128 bytes; so there are 2 encrypted blocks, the first 127 // The second byte is 1 byte int outputSize = cipher.getOutputSize(data.length);// Get the encrypted block size after encryption 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); // The doUpdate method is not available here. After viewing the source code, I found that there is no actual action after each doUpdate except putting byte[] in // In ByteArrayOutputStream, all byte[] are encrypted at the end of doFinal, but at this time the encrypted block size is likely to have exceeded // OutputSize so we had to use the dofinal method. i++; } return raw; } catch (Exception e) { throw new Exception(e.getMessage()); } } /** * * decrypt * * * @param key * decrypted key * * @param raw *encrypted data* * @return decrypted plaintext * * @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()); byte[] de_test = decrypt(getKeyPair().getPrivate(), en_test); System.out.println(new String(de_test)); } }
LoginAction.java
package RSA; //login /* * Generated by MyEclipse Struts * Template path: templates/java/JavaClass.vtl */ import java.math.BigInteger; import java.net.URLDecoder; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import RSA.RSAUtil; /** * MyEclipse Struts Creation date: 06-28-2008 * * XDoclet definition: * * @struts.action path="/login" name="loginForm" input="/login.jsp" * scope="request" validate="true" * @struts.action-forward name="error" path="/error.jsp" * @struts.action-forward name="success" path="/success.jsp" */ public class LoginAction { /* * Generated Methods */ /** * Method execute * * @param mapping * @param form * @param request * @param response * @return ActionForward */ public boolean execute(HttpServletRequest request, HttpServletResponse response) throws Exception { String pwd ; String result = request.getParameter("result"); System.out.println("The original text is encrypted: "); System.out.println(result); byte[] en_result = new BigInteger(result, 16).toByteArray(); //System.out.println("转成byte[]" + new String(en_result)); byte[] de_result = RSAUtil.decrypt(RSAUtil.getKeyPair().getPrivate(), en_result); System.out.println("Restore ciphertext:"); System.out.println(new String(de_result)); StringBuffer sb = new StringBuffer(); sb.append(new String(de_result)); pwd = sb.reverse().toString(); System.out.println(sb); System.out.println("================================="); pwd = URLDecoder.decode(pwd,"UTF-8");// System.out.println(pwd); request.setAttribute("pwd", pwd); return true; } }
Login login.jsp
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html:html lang="true"> <head> <title>login</title> <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 rsalogin(){ var thisPwd = document.getElementById("password").value; bodyRSA(); var result = encryptedString(key, encodeURIComponent(thisPwd)); //alert(encodeURIComponent(thisPwd)+"\r\n"+result); loginForm.action="loginCHK.jsp?result="+result; loginForm.submit(); } var key ; function bodyRSA(){ setMaxDigits(130); key = new RSAKeyPair("10001","","8246a46f44fc4d961e139fd70f4787d272d374532f4d2d9b7cbaad6a15a8c1301319aa6b3f30413b859351c71938aec516fa7147b69168b195e81df46b6bed7950cf3a1c719d42175f73d7c97a85d7d20a9e83688b92f05b3059bb2ff75cd7190a042cd2db97ebc2ab4da366f2a7085556ed613b5a39c9fdd2bb2595d1dc23b5"); } </script> </head> <body> <form method="post" name="loginForm" target=_blank> <table border="0"> <tr> <td> Password: </td> <td> <input type='text' name="password" id=password style='width:400px' value="my passwd"/> </td> </tr> <tr> <td colspan="2" align="center"> <input type="button" value="SUBMIT" onclick="rsalogin();" /> </td> </tr> </table> </form> </body> </html:html>
Login verification loginCHK.jsp
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <jsp:directive.page import="RSA.LoginAction"/> <% LoginAction la = new LoginAction(); la.execute(request ,response); %> pwd is [<%=request.getAttribute("pwd")%>]
In addition, digital signature can also be achieved through RSA : signature with private key and verification with public key. See the code for details:
package encode; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Signature; public class DigitalSignature2Example { public static void main(String[] args) { args = new String[] { "China" }; if (args.length != 1) { System.err.println("Usage:java DigitalSignature2Example "); System.exit(1); } try { byte[] plainText = args[0].getBytes("UTF-8"); System.out.println("\nStart generating RSA key."); // Generate RSA key pair KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); // initialize key length keyGen.initialize(1024); // generate key pair KeyPair pair = keyGen.generateKeyPair(); System.out.println("\nFinish generating RSA key."); // sign with private key Signature sig = Signature.getInstance("SHA1WithRSA"); // Initialize with the specified private key sig.initSign(pair.getPrivate()); // add the information to be signed sig.update(plainText); // return signed byte array byte[] signature = sig.sign(); System.out.println(sig.getProvider().getInfo()); System.out.println("\nSignature: "); System.out.println(new String(signature, "UTF-8")); // use public key authentication System.out.println("\nStart signature verification."); sig.initVerify(pair.getPublic()); // add the information to be verified sig.update(plainText); if (sig.verify(signature)) { System.out.println("Signature verificated."); } else { System.out.println("Signature failed."); } } catch (Exception e) { e.printStackTrace (); } } }