代碼:
import com.alibaba.fastjson.JSON; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import java.io.ByteArrayOutputStream; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import javax.crypto.Cipher; /** * <p> * RSA公鑰/私鑰/簽名工具包 * </p> * <p> * 羅納德·李維斯特(Ron [R]ivest)、阿迪·薩莫爾(Adi [S]hamir)和倫納德·阿德曼(Leonard [A]dleman) * </p> * <p> * 字符串格式的密鑰在未在特殊說明情況下都為BASE64編碼格式<br/> * 由於非對稱加密速度極其緩慢,一般文件不使用它來加密而是使用對稱加密,<br/> * 非對稱加密算法可以用來對對稱加密的密鑰加密,這樣保證密鑰的安全也就保證了數據的安全 * </p> * * @author Joe * @date 2019-4-15 * @version 1.0 */ public class RSAXUtils { /** * 加密算法RSA */ public static final String KEY_ALGORITHM = "RSA"; /** * 簽名算法 */ public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; /** * 獲取公鑰的key */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * 獲取私鑰的key */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; /** * <p> * 生成密鑰對(公鑰和私鑰) * </p> * * @return * @throws Exception */ public static Map<String, Object> genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * <p> * 用私鑰對信息生成數字簽名 * </p> * * @param data 已加密數據 * @param privateKey 私鑰(BASE64編碼) * * @return * @throws Exception */ public static String sign(byte[] data, String privateKey) throws Exception { byte[] keyBytes = decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateK); signature.update(data); return encode(signature.sign()); } /** * <p> * 校驗數字簽名 * </p> * * @param data 已加密數據 * @param publicKey 公鑰(BASE64編碼) * @param sign 數字簽名 * * @return * @throws Exception * */ public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(decode(sign)); } /** * <P> * 私鑰解密 * </p> * * @param encryptedData 已加密數據 * @param privateKey 私鑰(BASE64編碼) * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { byte[] keyBytes = decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對數據分段解密 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; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * <p> * 公鑰解密 * </p> * * @param encryptedData 已加密數據 * @param publicKey 公鑰(BASE64編碼) * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { byte[] keyBytes = decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對數據分段解密 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; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * <p> * 公鑰加密 * </p> * * @param data 源數據 * @param publicKey 公鑰(BASE64編碼) * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { byte[] keyBytes = decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); // 對數據加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對數據分段加密 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; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** * <p> * 私鑰加密 * </p> * * @param data 源數據 * @param privateKey 私鑰(BASE64編碼) * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { byte[] keyBytes = decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對數據分段加密 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; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** * <p> * 獲取私鑰 * </p> * * @param keyMap 密鑰對 * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encode(key.getEncoded()); } /** * <p> * 獲取公鑰 * </p> * * @param keyMap 密鑰對 * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encode(key.getEncoded()); } /** * <p> * BASE64字符串解碼為二進制數據 * </p> * * @param base64 * @return * @throws Exception */ public static byte[] decode(String base64) throws Exception { return new BASE64Decoder().decodeBuffer(base64); } /** * <p> * 二進制數據編碼為BASE64字符串 * </p> * * @param bytes * @return * @throws Exception */ public static String encode(byte[] bytes) { return new String(new BASE64Encoder().encode(bytes)); } /** * 按key進行正序排列,之間以&相連 * <功能描述> * @param params * @return */ public static String getSortParams(Map<String, Object> params) { Map<String, Object> map = new TreeMap<>(Comparator.naturalOrder()); map.putAll(params); StringBuffer stringBuffer = new StringBuffer(); map.forEach((k,v)-> stringBuffer.append(k).append("=").append(v).append("&")); String str = stringBuffer.toString(); if(str.length() > 0){ str = str.substring(0, str.length()-1); } return str; } public static void main(String[] args) throws Exception { baseTest(); // signDemo(); } /** * 基本測試 * @throws Exception */ private static void baseTest() throws Exception{ Map<String, Object> keyPair = genKeyPair(); // 公鑰 String publicKey = getPublicKey(keyPair); System.out.println("公鑰-------------"+publicKey); // 私鑰 String privateKey = getPrivateKey(keyPair); System.out.println("私鑰-------------"+privateKey); String source = "這是一行沒有任何意義的文字,你看完了等於沒看,不是嗎?"; // 簽名 String sign = RSAXUtils.sign(source.getBytes(), privateKey); System.err.println("簽名-------------" + sign); // 驗簽 boolean status = RSAXUtils.verify(source.getBytes(), publicKey, sign); System.err.println("驗證結果-------------" + status); } /** * 驗簽完整demo * @throws Exception */ private static void signDemo() throws Exception{ Map<String, Object> keyPair = genKeyPair(); // 公鑰 String publicKey = getPublicKey(keyPair); System.out.println("公鑰-------------"+publicKey); // 私鑰 String privateKey = getPrivateKey(keyPair); System.out.println("私鑰-------------"+privateKey); Map<String, Object> bizData = new HashMap<>(); bizData.put("autopay_flag", 1); bizData.put("order_no", "123456789"); bizData.put("order_status", 200); bizData.put("change_card_flag", 1); bizData.put("withdraw_flag", 0); Map<String,Object> params = new HashMap<>(); params.put("sign_type","RSA"); params.put("app_id","test"); params.put("version","1.0.0"); params.put("call","feedbackOrderStatus"); params.put("timestamp",String.valueOf(System.currentTimeMillis())); params.put("biz_data", JSON.toJSONString(bizData)); // 排序並拼接成字符串 String paramsStr = getSortParams(params); System.out.println("排序並拼接成字符串: " + paramsStr); // 簽名 long begin = System.currentTimeMillis(); System.err.println("簽名-------------begin=" + begin); String sign = RSAXUtils.sign(paramsStr.getBytes(), privateKey); long end = System.currentTimeMillis(); System.err.println("簽名-------------" + sign ); System.err.println("簽名-------------花費時間=" + (end - begin) + "ms"); params.put("sign", sign); System.out.println("post請求參數------------" + JSON.toJSONString(params)); // 開始驗簽----------------------------------------- Map<String,Object> params2 = JSON.parseObject(JSON.toJSONString(params), Map.class); // 驗簽需要去除sign params2.remove("sign"); // 排序並拼接成字符串 String paramsStr2 = getSortParams(params2); // 驗簽 boolean status = RSAXUtils.verify(paramsStr2.getBytes(), publicKey, sign); System.err.println("驗證結果-------------" + status); } }