1、RSA算法加密解密思路。
java后台隨機生成公鑰、私鑰。存儲於session中,告知前台js獲取公鑰。通過jsencrypt.min.js進行加密。傳輸回后台,后台通過私鑰解密。
2、RSA常見異常分解。
問題一
Cannot find any provider supporting RSA
出現此問題,屬於JDK版本bug問題,筆者1.8.0_171遇到此問題,更換1.8.0_211之后即可解決。
問題二
DER input, Integer tag error
出現此問題,主要是公鑰,私鑰混用到至,通過斷點發現解密時,用的公鑰進行解密,哈哈。
問題三
Decryption error
出現此問題,主要是前台頁面傳參至后台,出現“+”符號被替換成“ ”空格導致無法進行解密。
3.代碼部分。
<script language=javascript> var publicKey = '<%=session.getAttribute("publicKey")%>'; $(document).ready(function() { $('#doSearch').click(function(e) { var phoneNo= $("#phoneNo").val(); var encrypt = new JSEncrypt(); encrypt.setPublicKey(publicKey); phoneNo = encrypt.encrypt(phoneNo); alert(phoneNo);
document.frm.submit(); }); }); </script>
放入session部分
@RequestMapping(value = "/index") public String login(Model model, HttpSession session,HttpServletRequest request) { Map<String, String> rsaMap = new HashMap<String, String>(); rsaMap = RsaUtil.createRSAKeys(); String publicKey = rsaMap.get("publicKey"); String privateKey = rsaMap.get("privateKey"); session.setAttribute("publicKey", publicKey); session.setAttribute("niceKey", privateKey); return "index"; }
解析部分
@RequestMapping(value = "/search", method = RequestMethod.POST) public String search(@ModelAttribute String phoneNo, HttpServletRequest request, HttpSession session, Model model) { if (phoneNo==null || "".equals(phoneNo)) { model.addAttribute("returnUrl", "fail"); return "fail"; } //RSA解密 phoneNo = phoneNo.replace(" ", "+"); phoneNo = RsaUtil.decode(phoneNo, session.getAttribute("niceKey").toString()); System.out.println("phoneNo:" + phoneNo); { //業務代碼 } return "success"; }
RSA工具類部分
package com.thinksep.utils; 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.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.crypto.Cipher; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tomcat.util.codec.binary.Base64; /** * @author * @createDate */ public class RsaUtil { protected static final Log log = LogFactory.getLog(RsaUtil.class); private static String KEY_RSA_TYPE = "RSA"; private static int KEY_SIZE = 1024;//JDK方式RSA加密最大只有1024位 private static int ENCODE_PART_SIZE = KEY_SIZE/8; public static final String PUBLIC_KEY_NAME = "public"; public static final String PRIVATE_KEY_NAME = "private"; /** * 創建公鑰秘鑰 * @return */ public static Map<String,String> createRSAKeys(){ Map<String,String> keyPairMap = new HashMap<>();//里面存放公私秘鑰的Base64位加密 try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_RSA_TYPE); keyPairGenerator.initialize(KEY_SIZE,new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); //獲取公鑰秘鑰 String publicKeyValue = Base64.encodeBase64String(keyPair.getPublic().getEncoded()); String privateKeyValue = Base64.encodeBase64String(keyPair.getPrivate().getEncoded()); //存入公鑰秘鑰,以便以后獲取 keyPairMap.put(PUBLIC_KEY_NAME,publicKeyValue); keyPairMap.put(PRIVATE_KEY_NAME,privateKeyValue); } catch (NoSuchAlgorithmException e) { log.error("當前JDK版本沒找到RSA加密算法!"); e.printStackTrace(); } return keyPairMap; } /** * 公鑰加密 * 描述: * 1字節 = 8位; * 最大加密長度如 1024位私鑰時,最大加密長度為 128-11 = 117字節,不管多長數據,加密出來都是 128 字節長度。 * @param sourceStr * @param publicKeyBase64Str * @return */ public static String encode(String sourceStr,String publicKeyBase64Str){ byte [] publicBytes = Base64.decodeBase64(publicKeyBase64Str); //公鑰加密 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicBytes); List<byte[]> alreadyEncodeListData = new LinkedList<>(); int maxEncodeSize = ENCODE_PART_SIZE - 11; String encodeBase64Result = null; try { KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA_TYPE); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); Cipher cipher = Cipher.getInstance(KEY_RSA_TYPE); cipher.init(Cipher.ENCRYPT_MODE,publicKey); byte[] sourceBytes = sourceStr.getBytes("utf-8"); int sourceLen = sourceBytes.length; for(int i=0;i<sourceLen;i+=maxEncodeSize){ int curPosition = sourceLen - i; int tempLen = curPosition; if(curPosition > maxEncodeSize){ tempLen = maxEncodeSize; } byte[] tempBytes = new byte[tempLen];//待加密分段數據 System.arraycopy(sourceBytes,i,tempBytes,0,tempLen); byte[] tempAlreadyEncodeData = cipher.doFinal(tempBytes); alreadyEncodeListData.add(tempAlreadyEncodeData); } int partLen = alreadyEncodeListData.size();//加密次數 int allEncodeLen = partLen * ENCODE_PART_SIZE; byte[] encodeData = new byte[allEncodeLen];//存放所有RSA分段加密數據 for (int i = 0; i < partLen; i++) { byte[] tempByteList = alreadyEncodeListData.get(i); System.arraycopy(tempByteList,0,encodeData,i*ENCODE_PART_SIZE,ENCODE_PART_SIZE); } encodeBase64Result = Base64.encodeBase64String(encodeData); } catch (Exception e) { e.printStackTrace(); } return encodeBase64Result; } /** * 私鑰解密 * @param sourceBase64RSA * @param privateKeyBase64Str */ public static String decode(String sourceBase64RSA,String privateKeyBase64Str){ byte[] privateBytes = Base64.decodeBase64(privateKeyBase64Str); byte[] encodeSource = Base64.decodeBase64(sourceBase64RSA); int encodePartLen = encodeSource.length/ENCODE_PART_SIZE; List<byte[]> decodeListData = new LinkedList<>();//所有解密數據 String decodeStrResult = null; //私鑰解密 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateBytes); try { KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA_TYPE); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Cipher cipher = Cipher.getInstance(KEY_RSA_TYPE); cipher.init(Cipher.DECRYPT_MODE,privateKey); int allDecodeByteLen = 0;//初始化所有被解密數據長度 for (int i = 0; i < encodePartLen; i++) { byte[] tempEncodedData = new byte[ENCODE_PART_SIZE]; System.arraycopy(encodeSource,i*ENCODE_PART_SIZE,tempEncodedData,0,ENCODE_PART_SIZE); byte[] decodePartData = cipher.doFinal(tempEncodedData); decodeListData.add(decodePartData); allDecodeByteLen += decodePartData.length; } byte [] decodeResultBytes = new byte[allDecodeByteLen]; for (int i = 0,curPosition = 0; i < encodePartLen; i++) { byte[] tempSorceBytes = decodeListData.get(i); int tempSourceBytesLen = tempSorceBytes.length; System.arraycopy(tempSorceBytes,0,decodeResultBytes,curPosition,tempSourceBytesLen); curPosition += tempSourceBytesLen; } decodeStrResult = new String(decodeResultBytes,"UTF-8"); }catch (Exception e){ e.printStackTrace(); } return decodeStrResult; } }