1、RSA加密簡介java
RSA加密是一種非對稱加密。能夠在不直接傳遞密鑰的狀況下,完成解密。這可以確保信息的安全性,避免了直接傳遞密鑰所形成的被破解的風險。是由一對密鑰來進行加解密的過程,分別稱爲公鑰和私鑰。二者之間有數學相關,該加密算法的原理就是對一極大整數作因數分解的困難性來保證安全性。一般我的保存私鑰,公鑰是公開的(可能同時多人持有)。算法
2、RSA加密、簽名區別apache
加密和簽名都是爲了安全性考慮,但略有不一樣。常有人問加密和簽名是用私鑰仍是公鑰?其實都是對加密和簽名的做用有所混淆。簡單的說,加密是爲了防止信息被泄露,而簽名是爲了防止信息被篡改。這裏舉2個例子說明。安全
第一個場景:戰場上,B要給A傳遞一條消息,內容爲某一指令。性能
RSA的加密過程以下:編碼
(1)A生成一對密鑰(公鑰和私鑰),私鑰不公開,A本身保留。公鑰爲公開的,任何人能夠獲取。加密
(2)A傳遞本身的公鑰給B,B用A的公鑰對消息進行加密。spa
(3)A接收到B加密的消息,利用A本身的私鑰對消息進行解密。code
在這個過程當中,只有2次傳遞過程,第一次是A傳遞公鑰給B,第二次是B傳遞加密消息給A,即便都被敵方截獲,也沒有危險性,由於只有A的私鑰才能對消息進行解密,防止了消息內容的泄露。blog
第二個場景:A收到B發的消息後,須要進行回覆「收到」。
RSA簽名的過程以下:
(1)A生成一對密鑰(公鑰和私鑰),私鑰不公開,A本身保留。公鑰爲公開的,任何人能夠獲取。
(2)A用本身的私鑰對消息加簽,造成簽名,並將加簽的消息和消息自己一塊兒傳遞給B。
(3)B收到消息後,在獲取A的公鑰進行驗籤,若是驗簽出來的內容與消息自己一致,證實消息是A回覆的。
在這個過程當中,只有2次傳遞過程,第一次是A傳遞加簽的消息和消息自己給B,第二次是B獲取A的公鑰,即便都被敵方截獲,也沒有危險性,由於只有A的私鑰才能對消息進行簽名,即便知道了消息內容,也沒法僞造帶簽名的回覆給B,防止了消息內容的篡改。
可是,綜合兩個場景你會發現,第一個場景雖然被截獲的消息沒有泄露,可是能夠利用截獲的公鑰,將假指令進行加密,而後傳遞給A。第二個場景雖然截獲的消息不能被篡改,可是消息的內容能夠利用公鑰驗籤來得到,並不能防止泄露。因此在實際應用中,要根據狀況使用,也能夠同時使用加密和簽名,好比A和B都有一套本身的公鑰和私鑰,當A要給B發送消息時,先用B的公鑰對消息加密,再對加密的消息使用A的私鑰加簽名,達到既不泄露也不被篡改,更能保證消息的安全性。
總結:公鑰加密、私鑰解密、私鑰簽名、公鑰驗籤。
3、RSA加密、簽名的方法,代碼例子以下:
1 import java.io.ByteArrayOutputStream; 2 import java.security.KeyFactory; 3 import java.security.KeyPair; 4 import java.security.KeyPairGenerator; 5 import java.security.PrivateKey; 6 import java.security.PublicKey; 7 import java.security.Signature; 8 import java.security.spec.PKCS8EncodedKeySpec; 9 import java.security.spec.X509EncodedKeySpec; 10 import javax.crypto.Cipher; 11 import org.apache.commons.codec.binary.Base64; 12 13 public class TestRSA { 14 15 /** 16 * RSA最大加密明文大小 17 */ 18 private static final int MAX_ENCRYPT_BLOCK = 117; 19 20 /** 21 * RSA最大解密密文大小 22 */ 23 private static final int MAX_DECRYPT_BLOCK = 128; 24 25 /** 26 * 獲取密鑰對 27 * 28 * @return 密鑰對 29 */ 30 public static KeyPair getKeyPair() throws Exception { 31 KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); 32 generator.initialize(1024); 33 return generator.generateKeyPair(); 34 } 35 36 /** 37 * 獲取私鑰 38 * 39 * @param privateKey 私鑰字符串 40 * @return 41 */ 42 public static PrivateKey getPrivateKey(String privateKey) throws Exception { 43 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 44 byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes()); 45 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey); 46 return keyFactory.generatePrivate(keySpec); 47 } 48 49 /** 50 * 獲取公鑰 51 * 52 * @param publicKey 公鑰字符串 53 * @return 54 */ 55 public static PublicKey getPublicKey(String publicKey) throws Exception { 56 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 57 byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes()); 58 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey); 59 return keyFactory.generatePublic(keySpec); 60 } 61 62 /** 63 * RSA加密 64 * 65 * @param data 待加密數據 66 * @param publicKey 公鑰 67 * @return 68 */ 69 public static String encrypt(String data, PublicKey publicKey) throws Exception { 70 Cipher cipher = Cipher.getInstance("RSA"); 71 cipher.init(Cipher.ENCRYPT_MODE, publicKey); 72 int inputLen = data.getBytes().length; 73 ByteArrayOutputStream out = new ByteArrayOutputStream(); 74 int offset = 0; 75 byte[] cache; 76 int i = 0; 77 // 對數據分段加密 78 while (inputLen - offset > 0) { 79 if (inputLen - offset > MAX_ENCRYPT_BLOCK) { 80 cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK); 81 } else { 82 cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset); 83 } 84 out.write(cache, 0, cache.length); 85 i++; 86 offset = i * MAX_ENCRYPT_BLOCK; 87 } 88 byte[] encryptedData = out.toByteArray(); 89 out.close(); 90 // 獲取加密內容使用base64進行編碼,並以UTF-8爲標準轉化成字符串 91 // 加密後的字符串 92 return new String(Base64.encodeBase64String(encryptedData)); 93 } 94 95 /** 96 * RSA解密 97 * 98 * @param data 待解密數據 99 * @param privateKey 私鑰 100 * @return 101 */ 102 public static String decrypt(String data, PrivateKey privateKey) throws Exception { 103 Cipher cipher = Cipher.getInstance("RSA"); 104 cipher.init(Cipher.DECRYPT_MODE, privateKey); 105 byte[] dataBytes = Base64.decodeBase64(data); 106 int inputLen = dataBytes.length; 107 ByteArrayOutputStream out = new ByteArrayOutputStream(); 108 int offset = 0; 109 byte[] cache; 110 int i = 0; 111 // 對數據分段解密 112 while (inputLen - offset > 0) { 113 if (inputLen - offset > MAX_DECRYPT_BLOCK) { 114 cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK); 115 } else { 116 cache = cipher.doFinal(dataBytes, offset, inputLen - offset); 117 } 118 out.write(cache, 0, cache.length); 119 i++; 120 offset = i * MAX_DECRYPT_BLOCK; 121 } 122 byte[] decryptedData = out.toByteArray(); 123 out.close(); 124 // 解密後的內容 125 return new String(decryptedData, "UTF-8"); 126 } 127 128 /** 129 * 簽名 130 * 131 * @param data 待簽名數據 132 * @param privateKey 私鑰 133 * @return 簽名 134 */ 135 public static String sign(String data, PrivateKey privateKey) throws Exception { 136 byte[] keyBytes = privateKey.getEncoded(); 137 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); 138 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 139 PrivateKey key = keyFactory.generatePrivate(keySpec); 140 Signature signature = Signature.getInstance("MD5withRSA"); 141 signature.initSign(key); 142 signature.update(data.getBytes()); 143 return new String(Base64.encodeBase64(signature.sign())); 144 } 145 146 /** 147 * 驗籤 148 * 149 * @param srcData 原始字符串 150 * @param publicKey 公鑰 151 * @param sign 簽名 152 * @return 是否驗籤經過 153 */ 154 public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception { 155 byte[] keyBytes = publicKey.getEncoded(); 156 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 157 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 158 PublicKey key = keyFactory.generatePublic(keySpec); 159 Signature signature = Signature.getInstance("MD5withRSA"); 160 signature.initVerify(key); 161 signature.update(srcData.getBytes()); 162 return signature.verify(Base64.decodeBase64(sign.getBytes())); 163 } 164 165 public static void main(String[] args) { 166 try { 167 // 生成密鑰對 168 KeyPair keyPair = getKeyPair(); 169 String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded())); 170 String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded())); 171 System.out.println("私鑰:" + privateKey); 172 System.out.println("公鑰:" + publicKey); 173 // RSA加密 174 String data = "待加密的文字內容"; 175 String encryptData = encrypt(data, getPublicKey(publicKey)); 176 System.out.println("加密後內容:" + encryptData); 177 // RSA解密 178 String decryptData = decrypt(encryptData, getPrivateKey(privateKey)); 179 System.out.println("解密後內容:" + decryptData); 180 181 // RSA簽名 182 String sign = sign(data, getPrivateKey(privateKey)); 183 // RSA驗籤 184 boolean result = verify(data, getPublicKey(publicKey), sign); 185 System.out.print("驗簽結果:" + result); 186 } catch (Exception e) { 187 e.printStackTrace(); 188 System.out.print("加解密異常"); 189 } 190 } 191 }
PS:RSA加密對明文的長度有所限制,規定需加密的明文最大長度=密鑰長度-11(單位是字節,即byte),因此在加密和解密的過程當中須要分塊進行。而密鑰默認是1024位,即1024位/8位-11=128-11=117字節。因此默認加密前的明文最大長度117字節,解密密文最大長度爲128字。那麼爲啥二者相差11字節呢?是由於RSA加密使用到了填充模式(padding),即內容不足117字節時會自動填滿,用到填充模式天然會佔用必定的字節,並且這部分字節也是參與加密的。
密鑰長度的設置就是上面例子的第32行。可自行調整,固然非對稱加密隨着密鑰變長,安全性上升的同時性能也會有所降低。