RSA爲非對稱加密算法, 能夠實現對明文的加密與解密,但加密與解密使用的密鑰是不一樣的,分爲公鑰和私鑰,公鑰和私鑰必須配對使用,使用公鑰加密,私鑰解密;也能夠私鑰加密,公鑰解密,本文對RSA提供了代碼實現,也提供了一個小工具實現1024位密鑰的生成java
實例下載
工具集下載算法
RSA是非對稱性加密算法, 在瞭解非對稱性算法前,咱們先了解一下對稱算法數組
1.對稱算法:安全
1976年之前,全部的加密方法都是同一種模式:網絡
(1)甲方選擇某一種加密規則,對信息進行加密;dom
(2)乙方使用同一種規則,對信息進行解密。工具
因爲加密和解密使用一樣規則(簡稱"密鑰"),這被稱爲"對稱加密算法"(Symmetric-key algorithm)。測試
這種加密模式有一個最大弱點:甲方必須把加密規則告訴乙方,不然沒法解密。保存和傳遞密鑰,就成了最頭疼的問題編碼
2.非對稱性算法:加密
1976年,兩位美國計算機學家Whitfield Diffie 和 Martin Hellman,提出了一種嶄新構思,能夠在不直接傳遞密鑰的狀況下,完成解密。這被稱爲"Diffie-Hellman密鑰交換算法"。這個算法啓發了其餘科學家。人們認識到,加密和解密可使用不一樣的規則,只要這兩種規則之間存在某種對應關係便可,這樣就避免了直接傳遞密鑰。
這種新的加密模式被稱爲"非對稱加密算法"。
(1)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人均可以得到,私鑰則是保密的。
(2)甲方獲取乙方的公鑰,而後用它對信息加密。
(3)乙方獲得加密後的信息,用私鑰解密。
若是公鑰加密的信息只有私鑰解得開,那麼只要私鑰不泄漏,通訊就是安全的。
1977年,三位數學家Rivest、Shamir 和 Adleman 設計了一種算法,能夠實現非對稱加密。這種算法用他們三我的的名字命名,叫作RSA算法。從那時直到如今,RSA算法一直是最廣爲使用的"非對稱加密算法"。絕不誇張地說,只要有計算機網絡的地方,就有RSA算法。
這種算法很是可靠,密鑰越長,它就越難破解。根據已經披露的文獻,目前被破解的最長RSA密鑰是768個二進制位。也就是說,長度超過768位的密鑰,還沒法破解(至少沒人公開宣佈)。所以能夠認爲,1024位的RSA密鑰基本安全,2048位的密鑰極其安全。
本文對應的demo中,有一個工具,能夠利用其獲得1024位的密鑰, 也能夠獲得2048位的密鑰(見下圖)
本文只講解1024位的加解密, 2048位的加解密其它篇幅會講到(若是將2048位密鑰放到下面的測試代碼,會產生錯誤)
3. 加密,解密算法工具類
RSAUtils.java--RSA公鑰/私鑰/簽名工具包
此工具類也能夠根據算法生成上圖對應工具生成的 公鑰/私鑰 組
package com.wisdomdd.rsa; 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.HashMap; import java.util.Map; import javax.crypto.Cipher; /** * <p> * RSA公鑰/私鑰/簽名工具包 * </p> * <p> * 羅納德·李維斯特(Ron [R]ivest)、阿迪·薩莫爾(Adi [S]hamir)和倫納德·阿德曼(Leonard [A]dleman) * </p> * <p> * 字符串格式的密鑰在未在特殊說明狀況下都爲BASE64編碼格式<br/> * 因爲非對稱加密速度極其緩慢,通常文件不使用它來加密而是使用對稱加密,<br/> * 非對稱加密算法能夠用來對對稱加密的密鑰加密,這樣保證密鑰的安全也就保證了數據的安全 * </p> * * @author IceWee * @date 2012-4-26 * @version 1.0 */ public class RSAUtils { /** * 加密算法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 = Base64Utils.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 Base64Utils.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 = Base64Utils.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(Base64Utils.decode(sign)); } /** * <P> * 私鑰解密 * </p> * * @param encryptedData 已加密數據 * @param privateKey 私鑰(BASE64編碼) * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.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 = Base64Utils.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 = Base64Utils.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 = Base64Utils.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 Base64Utils.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 Base64Utils.encode(key.getEncoded()); } }
上面代碼使用到了Base64加密,下面提供 Base64Utils的代碼
Base64Utils.java--BASE64編碼解碼工具包
該工具類中用到了BASE64,須要藉助第三方類庫:javabase64-1.3.1.jar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 package com.wisdomdd.rsa; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import it.sauronsoftware.base64.Base64; /** * <p> * BASE64編碼解碼工具包 * </p> * <p> * 依賴javabase64-1.3.1.jar * </p> * * @author IceWee * @date 2012-5-19 * @version 1.0 */ public class Base64Utils { /** * 文件讀取緩衝區大小 */ private static final int CACHE_SIZE = 1024; /** * <p> * BASE64字符串解碼爲二進制數據 * </p> * * @param base64 * @return * @throws Exception */ public static byte[] decode(String base64) throws Exception { return Base64.decode(base64.getBytes()); } /** * <p> * 二進制數據編碼爲BASE64字符串 * </p> * * @param bytes * @return * @throws Exception */ public static String encode(byte[] bytes) throws Exception { return new String(Base64.encode(bytes)); } /** * <p> * 將文件編碼爲BASE64字符串 * </p> * <p> * 大文件慎用,可能會致使內存溢出 * </p> * * @param filePath * 文件絕對路徑 * @return * @throws Exception */ public static String encodeFile(String filePath) throws Exception { byte[] bytes = fileToByte(filePath); return encode(bytes); } /** * <p> * BASE64字符串轉回文件 * </p> * * @param filePath * 文件絕對路徑 * @param base64 * 編碼字符串 * @throws Exception */ public static void decodeToFile(String filePath, String base64) throws Exception { byte[] bytes = decode(base64); byteArrayToFile(bytes, filePath); } /** * <p> * 文件轉換爲二進制數組 * </p> * * @param filePath * 文件路徑 * @return * @throws Exception */ public static byte[] fileToByte(String filePath) throws Exception { byte[] data = new byte[0]; File file = new File(filePath); if (file.exists()) { FileInputStream in = new FileInputStream(file); ByteArrayOutputStream out = new ByteArrayOutputStream(2048); byte[] cache = new byte[CACHE_SIZE]; int nRead = 0; while ((nRead = in.read(cache)) != -1) { out.write(cache, 0, nRead); out.flush(); } out.close(); in.close(); data = out.toByteArray(); } return data; } /** * <p> * 二進制數據寫文件 * </p> * * @param bytes * 二進制數據 * @param filePath * 文件生成目錄 */ public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { InputStream in = new ByteArrayInputStream(bytes); File destFile = new File(filePath); if (!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } destFile.createNewFile(); OutputStream out = new FileOutputStream(destFile); byte[] cache = new byte[CACHE_SIZE]; int nRead = 0; while ((nRead = in.read(cache)) != -1) { out.write(cache, 0, nRead); out.flush(); } out.close(); in.close(); } }
上面提供了RSA工具類的代碼,
下面使用示例代碼講解 加密/解密 示例代碼
--這裏使用代碼得到公鑰私鑰,也可使用工具得到配對的公鑰私鑰
Map<String, Object> keyMap = RSAUtils.genKeyPair();
String publicKey = RSAUtils.getPublicKey(keyMap); ----得到RSA公鑰
String privateKey = RSAUtils.getPrivateKey(keyMap); ----得到RSA私鑰
RSAUtils.encryptByPrivateKey(data, publicKey); ----私鑰加密
RSAUtils.decryptByPublicKey(encodedData, privateKey); ----公鑰解密
RSAUtils.encryptByPublicKey(data, publicKey); ----公鑰加密
RSAUtils.decryptByPrivateKey(encodedData, privateKey); ----私鑰解密
package com.wisdomdd.rsa; import java.util.Map; public class RSATester { static String publicKey; static String privateKey; static { try { Map<String, Object> keyMap = RSAUtils.genKeyPair(); publicKey = RSAUtils.getPublicKey(keyMap); privateKey = RSAUtils.getPrivateKey(keyMap); System.err.println("公鑰: \n\r" + publicKey); System.err.println("私鑰: \n\r" + privateKey); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { test(); //testSign(); //testHttpSign(); } static void test() throws Exception { System.err.println("公鑰加密——私鑰解密"); String source = "這是一行沒有任何意義的文字,你看完了等於沒看,不是嗎?"; System.out.println("\r加密前文字:\r\n" + source); byte[] data = source.getBytes(); byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey); System.out.println("加密後文字:\r\n" + new String(encodedData)); byte[] decodedData = RSAUtils.decryptByPrivateKey(encodedData, privateKey); String target = new String(decodedData); System.out.println("解密後文字: \r\n" + target); String sign = RSAUtils.sign(encodedData, privateKey); boolean status = RSAUtils.verify(encodedData, publicKey, sign); System.err.println("驗證結果:\r" + status); } static void testSign() throws Exception { System.err.println("私鑰加密——公鑰解密"); String source = "這是一行測試RSA數字簽名的無心義文字"; System.out.println("原文字:\r\n" + source); byte[] data = source.getBytes(); byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey); System.out.println("加密後:\r\n" + new String(encodedData)); byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey); String target = new String(decodedData); System.out.println("解密後: \r\n" + target); System.err.println("私鑰簽名——公鑰驗證簽名"); String sign = RSAUtils.sign(encodedData, privateKey); System.err.println("簽名:\r" + sign); boolean status = RSAUtils.verify(encodedData, publicKey, sign); System.err.println("驗證結果:\r" + status); } static void testHttpSign() throws Exception { String param = "id=1&name=張三"; byte[] encodedData = RSAUtils.encryptByPrivateKey(param.getBytes(), privateKey); System.out.println("加密後:" + encodedData); byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey); System.out.println("解密後:" + new String(decodedData)); String sign = RSAUtils.sign(encodedData, privateKey); System.err.println("簽名:" + sign); boolean status = RSAUtils.verify(encodedData, publicKey, sign); System.err.println("簽名驗證結果:" + status); } }