本文實例講述了Java RSA加密解密實現方法。分享給大家供大家參考,具體如下:
該工具類中用到了BASE64,需要借助第三方類庫:javabase64-1.3.1.jar
javabase64-1.3.1.jar 本站下載地址。
注意:
RSA加密明文最大長度117字節,解密要求密文最大長度為128字節,所以在加密和解密的過程中需要分塊進行。
RSA加密對明文的長度是有限制的,如果加密數據過大會拋出如下異常:
1
2
3
4
|
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes at com.sun.crypto.provider.RSACipher.a(DashoA13*..) at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) |
RSAUtils.java
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
|
package security; 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()); } } |
Base64Utils.java
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
|
package security; 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(); } } |
RSATester.java
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
|
package security; 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(); } 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); } 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); } } |
希望本文所述對大家java程序設計有所幫助。
原文鏈接:http://blog.csdn.net/centralperk/article/details/8538697