First, briefly clarify the difference between symmetric encryption and asymmetric encryption:
Symmetric encryption: that is, the same key is used for encryption and decryption;
Asymmetric encryption: two keys are generated. The public key is used for encryption and the private key is used for decryption;
Note: the encryption operation in this practice mainly generates the following three key objects
1. Encryption module
2. Encrypted public key
3. Encrypt private key
Idea: the function of public key is to encrypt the specified string; The private key decrypts the specified string; Each time the foreground sends an http request to the background, the newly generated encryption module, encryption public key and encryption private key will be sent to the foreground to encrypt the data; The private key is kept waiting in the background. After the current station encrypts with the public key, the data is transmitted to the background, and then decrypted with the reserved private key.
Note: the encryption module, encryption public key and encryption private key generated each time are combined. If they are not generated at the same time, the packet decryption will fail!
Next, I will summarize all the encryption and decryption in the foreground and background, and make flexible changes according to the actual development situation:
Tool class: create a new tool class for data conversion
public class HexUtil { /** * Binary byte array to hexadecimal byte array * byte array to hex * * @param b byte array * @return hex string */ public static String byte2hex(byte[] b) { StringBuilder hs = new StringBuilder(); String stmp; for (int i = 0; i < b.length; i++) { stmp = Integer.toHexString(b[i] & 0xFF).toUpperCase(); if (stmp.length() == 1) { hs.append("0").append(stmp); } else { hs.append(stmp); } } return hs.toString(); } /** * Hexadecimal byte array to binary byte array * hex to byte array * * @param hex hex string * @return byte array */ public static byte[] hex2byte(String hex) throws IllegalArgumentException{ if (hex.length() % 2 != 0) { throw new IllegalArgumentException ("invalid hex string"); } char[] arr = hex.toCharArray(); byte[] b = new byte[hex.length() / 2]; for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) { String swap = "" + arr[i++] + arr[i]; int byteint = Integer.parseInt(swap, 16) & 0xFF; b[j] = new Integer(byteint).byteValue(); } return b; } public static String bytesToHexString(byte[] src){ StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } private static byte charToByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } public static byte[] hexStringToBytes(String hexString) { if (hexString == null || hexString.equals("")) { return null; } hexString = hexString.toUpperCase(); int length = hexString.length() / 2; char[] hexChars = hexString.toCharArray(); byte[] d = new byte[length]; for (int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } }
Core: RSA encryption class
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 java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; /** * RSA Tool class. Provide encryption, decryption and key generation methods. * Need to Download bcprov-jdk14-123 jar. * */ public class RSAUtils { private static final int MAX_ENCRYPT_BLOCK = 117; // RSA maximum encrypted plaintext size private static final int MAX_DECRYPT_BLOCK = 128; // RSA maximum decryption ciphertext size /** * Generate public and private keys * * @throws NoSuchAlgorithmException */ public static KeyPair genRSAKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(1024); return keyPairGen.generateKeyPair(); } /** * Generate RSA public key using modulus and exponent * Note: [this code uses the default filling method, RSA/None/PKCS1Padding. The default filling method may be different for different jdks. For example, RSA is the default for Android * /None/NoPadding] * * @param modulus model * @param exponent index * @return */ public static RSAPublicKey getPublicKey(String modulus, String exponent) { try { BigInteger b1 = new BigInteger(modulus, 16); BigInteger b2 = new BigInteger(exponent, 16); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2); return (RSAPublicKey) keyFactory.generatePublic(keySpec); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Generate RSA private key using modulus and exponent * Note: [this code uses the default filling method, RSA/None/PKCS1Padding. The default filling method may be different for different jdks. For example, RSA is the default for Android * /None/NoPadding] * * @param modulus model * @param exponent index * @return */ public static RSAPrivateKey getPrivateKey(String modulus, String exponent) { try { BigInteger b1 = new BigInteger(modulus, 16); BigInteger b2 = new BigInteger(exponent, 16); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2); return (RSAPrivateKey) keyFactory.generatePrivate(keySpec); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Public key encryption */ public static byte[] encryptByPublicKey(byte[] data, RSAPublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); int inputLen = data.length; try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { int offSet = 0; byte[] cache; int i = 0; // Segment encryption of data while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } return out.toByteArray(); } } /** * Private key decryption */ public static String decryptByPrivateKey(byte[] encryptedData, RSAPrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); int inputLen = encryptedData.length; try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { int offSet = 0; byte[] cache; int i = 0; // Decrypt data segments while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } return new String(out.toByteArray(), "utf-8"); } } /** * ASCII Code to BCD code */ public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) { byte[] bcd = new byte[asc_len / 2]; int j = 0; for (int i = 0; i < (asc_len + 1) / 2; i++) { bcd[i] = asc_to_bcd(ascii[j++]); bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4)); } return bcd; } public static byte asc_to_bcd(byte asc) { byte bcd; if ((asc >= '0') && (asc <= '9')) bcd = (byte) (asc - '0'); else if ((asc >= 'A') && (asc <= 'F')) bcd = (byte) (asc - 'A' + 10); else if ((asc >= 'a') && (asc <= 'f')) bcd = (byte) (asc - 'a' + 10); else bcd = (byte) (asc - 48); return bcd; } /** * BCD To string */ public static String bcd2Str(byte[] bytes) { char temp[] = new char[bytes.length * 2], val; for (int i = 0; i < bytes.length; i++) { val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f); temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0'); val = (char) (bytes[i] & 0x0f); temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0'); } return new String(temp); } /** * Split string */ public static String[] splitString(String string, int len) { int x = string.length() / len; int y = string.length() % len; int z = 0; if (y != 0) { z = 1; } String[] strings = new String[x + z]; String str = ""; for (int i = 0; i < x + z; i++) { if (i == x + z - 1 && y != 0) { str = string.substring(i * len, i * len + y); } else { str = string.substring(i * len, i * len + len); } strings[i] = str; } return strings; } /** * split array */ public static byte[][] splitArray(byte[] data, int len) { int x = data.length / len; int y = data.length % len; int z = 0; if (y != 0) { z = 1; } byte[][] arrays = new byte[x + z][]; byte[] arr; for (int i = 0; i < x + z; i++) { arr = new byte[len]; if (i == x + z - 1 && y != 0) { System.arraycopy(data, i * len, arr, 0, y); } else { System.arraycopy(data, i * len, arr, 0, len); } arrays[i] = arr; } return arrays; } //String decryption public static String Decrypt(String str,String mou,String m) throws Exception{ //Modular hex String modulus =mou; //Private key index hex String private_exponent = m; RSAPrivateKey priKey = getPrivateKey(modulus, private_exponent); return decryptByPrivateKey(HexUtil.hexStringToBytes(str), priKey); } //Get module information public static Map getModulus () throws NoSuchAlgorithmException{ KeyPair keyPair = genRSAKeyPair(); Map map = new HashMap(); //Generate public and private keys RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); //Modular hex String modulus = publicKey.getModulus().toString(16); //Public key index hex String public_exponent = publicKey.getPublicExponent().toString(16); //Private key index hex String private_exponent = privateKey.getPrivateExponent().toString(16); map.put("g", public_exponent); map.put("m", private_exponent); map.put("modu", modulus); return map; } public static void main(String[] args) throws Exception { KeyPair keyPair = genRSAKeyPair(); //Generate public and private keys RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); //Modular hex String modulus = publicKey.getModulus().toString(16); //Public key index hex String public_exponent = publicKey.getPublicExponent().toString(16); //Private key index hex String private_exponent = privateKey.getPrivateExponent().toString(16); System.out.println("public_modulus: " + modulus); System.out.println("public_exponent: " + public_exponent); System.out.println("private_exponent: " + private_exponent); //Plaintext String plaintStr = "123456"; System.out.println("plaintStr: " + plaintStr); //Generating public and private keys using modulus and exponent RSAPublicKey pubKey = getPublicKey(modulus, public_exponent); RSAPrivateKey priKey = getPrivateKey(modulus, private_exponent); //Ciphertext encrypted by public key byte[] encryptStr = encryptByPublicKey(plaintStr.getBytes("utf-8"), pubKey); System.out.println("encryptStr: " + HexUtil.bytesToHexString(encryptStr)); String jmh = HexUtil.bytesToHexString(encryptStr); System.out.println("start"); //Plaintext after decryption of private key System.out.println("decryptStr: " + decryptByPrivateKey(HexUtil.hexStringToBytes(jmh), priKey)); } }
Business logic class 1
//Declare encryption key private static String m; //Claim encryption module private static String mou; //2 //Call the getmodule method of RSA tool class to obtain the supporting public key, secret key and encryption module information, and transfer the public key and encryption module to the foreground, secret key and encryption module //Save to background @ResponseBody @RequestMapping(value = "/getMoudle", method = RequestMethod.POST) public Object getMoudle() throws NoSuchAlgorithmException { Map jmInfo = RSAUtils.getModulus(); String my = jmInfo.getString("m"); m = my; mou = jmInfo.getString("modu"); return jmInfo; }
JS page send request
//1 //Mapping js package <script language="JavaScript" type="text/javascript" src="http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js"></script> <script language="JavaScript" type="text/javascript" src="http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js"></script> <script language="JavaScript" type="text/javascript" src="http://www-cs-students.stanford.edu/~tjw/jsbn/prng4.js"></script> <script language="JavaScript" type="text/javascript" src="http://www-cs-students.stanford.edu/~tjw/jsbn/rng.js"></script> <script language="JavaScript" type="text/javascript" src="http://www-cs-students.stanford.edu/~tjw/jsbn/rsa.js"></script> <script language="JavaScript" type="text/javascript" src="http://www-cs-students.stanford.edu/~tjw/jsbn/rsa2.js"></script> //2 declare encrypted objects var RSADo = { "modulus":"", "publicExponent":""} //3 get encrypted information $(function() { $("#denglu").bind("click", function() { $.ajax("/..../....",{ data :{ }, dataType: 'json', //The server returns json format data async: false, type: 'post', //HTTP request type timeout: 10000, //The timeout is set to 10 seconds; success: function (data) { RSADo.modulus = data.modu; RSADo.publicExponent = data.g; //privateKey = data.m; var userName = $("#userName").val(); var possWord = $("#iptPwd").val(); //Encrypt with the obtained public key var rsa = new RSAKey(); rsa.setPublic(RSADo.modulus, RSADo.publicExponent); var Name = rsa.encrypt(userName); var pwd = rsa.encrypt(possWord); console.log('After encryption( name): ', Name); console.log('After encryption( pwd): ', pwd); //Private key decryption //Usually, the private key will not be obtained and decrypted at the front desk, but this situation will be listed //rsa.setPrivate(RSADo.modulus, RSADo.publicExponent, privateKey) //var decryptStr = rsa.decrypt(encryptStr) //console.log('decrypt private key: ', privateKey) //console.log('decrypt ', decryptStr) //The current account password is set to the state after RSA encryption, otherwise the plaintext will still be exposed $('#userName').val(Name); $('#iptPwd').val(pwd); //Execute the submit function and enter the background again $('#form').submit(); }, error: function (xhr, type, errorThrown) { } }); }); //Declare public key encryption method function encryption(str){ // RSA object generation by instantiating js var rsa = new RSAKey() rsa.setPublic(RSADo.modulus, RSADo.publicExponent) var encryptStr = rsa.encrypt(str); return encryptStr; }
Some relatively old frameworks may directly put business logic classes into encryption classes and execute them together
Note the static attribute of this declaration, which is used to store the key and encryption module
Some framework requests cannot simply throw exceptions but catch exceptions for foreground requests, and the return type needs to be encapsulated into a json string to return without errors. There are many strange problems
//Declare encryption key private static String m; //Claim encryption module private static String mou; @Action public String getModule() { Map jmInfo = new HashMap(); try { jmInfo = MainPage.getModulus(); String my = jmInfo.get("m").toString(); m = my; mou = jmInfo.get("modu").toString(); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } JSONObject json = new JSONObject(); json.putAll(jmInfo); return json.toString(); }
Corresponding to the summary of all the above main methods, make another simplification
public static void main(String[] args) throws Exception { HttpServletRequest req = ActionContext.getActionContext().getHttpServletRequest(); HttpServletResponse resp = ActionContext.getActionContext().getHttpServletResponse(); String userName = req.getParameter(System.getProperty(user name)); String possWord = req.getParameter(System.getProperty(password)); //Make a non empty judgment of account and password if(!StringUtility.isNullOrEmpty(userName) && !StringUtility.isNullOrEmpty(possWord)) { //Normally, we don't need to use the getMoudles() method twice to establish the key //The static attributes stored above should be applied directly (private key -- m, encryption module -- mou) //Otherwise, there will be an error of decryption failure, because two sets of keys will be created again //Generate private key using modulus and exponent RSAPrivateKey priKey = getPrivateKey(mou, m); System.out.println("Start decryption"); //Plaintext after decryption of private key System.out.println("decryptName: " + decryptByPrivateKey(HexUtil.hexStringToBytes(Name), priKey)); System.out.println("decryptPwd: " + decryptByPrivateKey(HexUtil.hexStringToBytes(Pwd), priKey)); String decryptName = decryptByPrivateKey(HexUtil.hexStringToBytes(userName), priKey); String decryptPwd = decryptByPrivateKey(HexUtil.hexStringToBytes(possWord), priKey); //After that, take the decrypted account and password, verify it, and then log in } }
This summary is relatively detailed. It is mainly clear that to produce a set of keys, you can perform encryption and decryption operations in this set of keys. If you add a new set of keys in the main program, it will never match.
Of course, in most cases, the foreground requests to obtain the encryption module and public key, while the private key and encryption module are stored in the defined static attributes; When logging in, transfer the data to the background for confirmation, and directly call the static attribute to decrypt; This paper summarizes that the encryption and decryption of all situations is also for the diversity of situations in case of emergency~