RSA 
    这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。 
    这种加密算法的特点主要是密钥的变化,上文我们看到DES只有一个密钥。相当于只有一把钥匙,如果这把钥匙丢了,数据也就不安全了。RSA同时有两把钥匙,公钥与私钥。同时支持数字签名。数字签名的意义在于,对传输过来的数据进行校验。确保数据在传输工程中不被修改。

流程分析:  

  1. 甲方构建密钥对儿,将公钥公布给乙方,将私钥保留。
  2. 甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。
  3. 乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。

按如上步骤给出序列图,如下: 



通过java代码实现如下:



1. package com.somnus.cipher;  
2.
3. import java.io.InputStream;
4. import java.security.Key;
5. import java.security.KeyFactory;
6. import java.security.KeyPair;
7. import java.security.KeyPairGenerator;
8. import java.security.PrivateKey;
9. import java.security.PublicKey;
10. import java.security.Signature;
11. import java.security.interfaces.RSAPrivateKey;
12. import java.security.interfaces.RSAPublicKey;
13. import java.security.spec.PKCS8EncodedKeySpec;
14. import java.security.spec.X509EncodedKeySpec;
15. import java.util.Arrays;
16. import java.util.HashMap;
17. import java.util.Map;
18.
19. import javax.crypto.Cipher;
20.
21. import org.apache.commons.codec.binary.Base64;
22. import org.apache.commons.codec.binary.Hex;
23.
24. /** 非对称加密算法RSA
25. * @Title: RsaEncrypt.java
26. * @Description: TODO
27. * @author Somnus
28. * @date 2015年6月5日 下午2:02:44
29. * @version V1.0
30. */
31. public class RSAUtil {
32. public static final String ALGORITHM = "RSA";
33. public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
34.
35. private static final String PUBLIC_KEY = "RSAPublicKey";
36. private static final String PRIVATE_KEY = "RSAPrivateKey";
37.
38. private static final String PUBLIC_KEY_PATH = "public.cer";
39. private static final String PRIVATE_KEY_PATH = "private.key";
40.
41. /**
42. * 用私钥对信息生成数字签名
43. *
44. * @param data
45. * 加密数据
46. * @param privateKey
47. * 私钥
48. * @return
49. * @throws Exception
50. */
51. public static String sign(String data) throws Exception {
52. // 解密由base64编码的私钥
53. byte[] keyBytes = Base64.decodeBase64(getPrivateKey());
54. // 构造PKCS8EncodedKeySpec对象
55. new PKCS8EncodedKeySpec(keyBytes);
56. // ALGORITHM 指定的加密算法
57. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
58. // 取私钥匙对象
59. PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
60. // 用私钥对信息生成数字签名
61. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
62. signature.initSign(priKey);
63. signature.update(Hex.decodeHex(data.toCharArray()));
64. return Base64.encodeBase64String(signature.sign());
65. }
66.
67. /**
68. * 校验数字签名
69. *
70. * @param data
71. * 加密数据
72. * @param publicKey
73. * 公钥
74. * @param sign
75. * 数字签名
76. *
77. * @return 校验成功返回true 失败返回false
78. * @throws Exception
79. *
80. */
81. public static boolean verify(String data,String sign)throws Exception {
82. // 解密由base64编码的公钥
83. byte[] keyBytes = Base64.decodeBase64(getPublicKey());
84. // 构造X509EncodedKeySpec对象
85. new X509EncodedKeySpec(keyBytes);
86. // ALGORITHM 指定的加密算法
87. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
88. // 取公钥匙对象
89. PublicKey pubKey = keyFactory.generatePublic(keySpec);
90. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
91. signature.initVerify(pubKey);
92. signature.update(Hex.decodeHex(data.toCharArray()));
93. // 验证签名是否正常
94. return signature.verify(Base64.decodeBase64(sign));
95. }
96.
97. /**
98. * 解密<br>
99. * 用私钥解密
100. *
101. * @param data
102. * @return
103. * @throws Exception
104. */
105. public static String decryptByPrivateKey(String data)throws Exception {
106. // 对密钥解密
107. byte[] keyBytes = Base64.decodeBase64(getPrivateKey());
108. // 取得私钥
109. new PKCS8EncodedKeySpec(keyBytes);
110. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
111. Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
112. //初始化Cipher对象,设置为解密模式
113. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
114. cipher.init(Cipher.DECRYPT_MODE, privateKey);
115. // 执行解密操作
116. byte[] buff = cipher.doFinal(Hex.decodeHex(data.toCharArray()));
117. System.out.println(Arrays.toString(buff));
118. return new String(buff);
119. }
120.
121. /**
122. * 解密<br>
123. * 用公钥解密
124. *
125. * @param data
126. * @return
127. * @throws Exception
128. */
129. public static String decryptByPublicKey(String data)throws Exception {
130. // 对密钥解密
131. byte[] keyBytes = Base64.decodeBase64(getPublicKey());
132. // 取得公钥
133. new X509EncodedKeySpec(keyBytes);
134. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
135. Key publicKey = keyFactory.generatePublic(x509KeySpec);
136. //初始化Cipher对象,设置为解密模式
137. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
138. cipher.init(Cipher.DECRYPT_MODE, publicKey);
139. // 执行解密操作
140. byte[] buff = cipher.doFinal(Hex.decodeHex(data.toCharArray()));
141. System.out.println(Arrays.toString(buff));
142. return new String(buff);
143. }
144.
145. /**
146. * 加密<br>
147. * 用公钥加密
148. *
149. * @param data
150. * @return
151. * @throws Exception
152. */
153. public static String encryptByPublicKey(String data)throws Exception {
154. // 对公钥解密
155. byte[] keyBytes = Base64.decodeBase64(getPublicKey());
156. // 取得公钥
157. new X509EncodedKeySpec(keyBytes);
158. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
159. Key publicKey = keyFactory.generatePublic(x509KeySpec);
160. // 实例化Cipher对象,它用于完成实际的加密操作
161. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
162. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
163. byte[] buff = cipher.doFinal(data.getBytes());
164. System.out.println(Arrays.toString(buff));
165. // 执行加密操作。加密后的结果通常都会用Base64编码进行传输
166. return Hex.encodeHexString(buff);
167. }
168.
169. /**
170. * 加密<br>
171. * 用私钥加密
172. *
173. * @param data
174. * @return
175. * @throws Exception
176. */
177. public static String encryptByPrivateKey(String data) throws Exception {
178. // 对密钥解密
179. byte[] keyBytes = Base64.decodeBase64(getPrivateKey());
180. // 取得私钥
181. new PKCS8EncodedKeySpec(keyBytes);
182. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
183. Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
184. // 对数据加密
185. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
186. cipher.init(Cipher.ENCRYPT_MODE, privateKey);
187. byte[] buff = cipher.doFinal(data.getBytes());
188. System.out.println(Arrays.toString(buff));
189. // 执行加密操作。加密后的结果通常都会用Base64编码进行传输
190. return Hex.encodeHexString(buff);
191. }
192.
193. /**
194. * 取得私钥
195. *
196. * @param keyMap
197. * @return
198. * @throws Exception
199. */
200. public static String getPrivateKey()throws Exception{
201. Key key = (Key)initKey().get(PRIVATE_KEY);
202. return Base64.encodeBase64String(key.getEncoded());
203. }
204.
205. /**
206. * 取得公钥
207. *
208. * @param keyMap
209. * @return
210. * @throws Exception
211. */
212. public static String getPublicKey()throws Exception {
213. Key key = (Key) initKey().get(PUBLIC_KEY);
214. return Base64.encodeBase64String(key.getEncoded());
215. }
216.
217. /**
218. * 初始化密钥
219. *
220. * @return
221. * @throws Exception
222. * @throws Exception
223. */
224. public static Map<String, Object> initKey() throws Exception{
225. class.getClassLoader().getResourceAsStream(PUBLIC_KEY_PATH);
226. class.getClassLoader().getResourceAsStream(PRIVATE_KEY_PATH);
227. try {
228. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
229. /*生成公钥*/
230. byte[] encodedpubkey = new byte[in1.available()];
231. in1.read(encodedpubkey);
232. new X509EncodedKeySpec(encodedpubkey);
233. PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
234. /*生成私钥*/
235. byte[] encodedprikey = new byte[in2.available()];
236. in2.read(encodedprikey);
237. new PKCS8EncodedKeySpec(encodedprikey);
238. PrivateKey privateKey = keyFactory.generatePrivate(priKeySpec);
239. /*封装进map*/
240. new HashMap<String, Object>();
241. keyMap.put(PUBLIC_KEY, publicKey);
242. keyMap.put(PRIVATE_KEY, privateKey);
243. return keyMap;
244. catch(Exception e){
245. e.printStackTrace();
246. throw e;
247. finally {
248. in1.close();
249. in2.close();
250. }
251. }
252. /**
253. * 初始化密钥 2
254. * @return
255. * @throws Exception
256. */
257. public static Map<String, Object> initKey2() throws Exception {
258. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
259. 1024);
260. KeyPair keyPair = keyPairGen.generateKeyPair();
261. // 公钥
262. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
263. // 私钥
264. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
265. new HashMap<String, Object>(2);
266. keyMap.put(PUBLIC_KEY, publicKey);
267. keyMap.put(PRIVATE_KEY, privateKey);
268. return keyMap;
269. }
270.
271. public static void main(String[] args) throws Exception {
272. String publicKey = getPublicKey();
273. String privateKey = getPrivateKey();
274. "公钥:\r" + publicKey);
275. "私钥:\r" + privateKey);
276.
277. "公钥加密————————————————————私钥解密");
278. "Somnus";
279. "原文: " + data);
280. String encryptData = encryptByPublicKey(data);
281. "加密后: " + encryptData);
282. String decryptData = decryptByPrivateKey(encryptData);
283. "解密后: " + decryptData);
284.
285. "私钥加密————————————————————公钥解密");
286. "原文: " + data);
287. String encryptData2 = encryptByPrivateKey(data);
288. "加密后: " + encryptData2);
289. String decryptData2 = decryptByPublicKey(encryptData2);
290. "解密后: " + decryptData2);
291.
292. "私钥签名——公钥验证签名");
293. // 产生签名
294. String sign = sign(encryptData2);
295. "签名:\r" + sign);
296. // 验证签名
297. boolean status = verify(encryptData2,sign);
298. "状态:" + status);
299. }
300. }

控制台输出: 


1. 公钥加密————————————————————私钥解密  
2. 原文: Somnus
3. [82, 112, 47, -49, -44, 28, 117, 87, -32, -5, -116, 56, -60, 87, -1, -36, 89, 84, -9, 17, -66, 64, -115, -114, 72, -86, 79, 63, -15, -35, -14, 40, -50, 16, -105, 73, 80, 7, -48, 75, -114, -64, 80, 74, 6, -74, 24, -59, -59, 31, 121, -63, 45, 93, 20, 25, -116, 51, -74, -40, 22, 55, -31, -106]
4. 加密后: 52702fcfd41c7557e0fb8c38c457ffdc5954f711be408d8e48aa4f3ff1ddf228ce1097495007d04b8ec0504a06b618c5c51f79c12d5d14198c33b6d81637e196
5. [83, 111, 109, 110, 117, 115]
6. 解密后: Somnus
7. 私钥加密————————————————————公钥解密
8. 原文: Somnus
9. [69, -38, -21, -84, -56, -1, 50, -33, -46, 11, 124, 37, -106, 53, 67, 81, -9, 39, -15, -89, 59, -49, 102, 71, 89, -7, 22, 42, 49, -29, 28, 114, -36, -1, -123, -7, 124, -104, -38, 83, 12, 76, 61, -117, 118, -54, 99, 99, 47, -118, 28, -119, 83, -5, 124, 122, -3, 109, 45, -38, -31, 98, 99, -107]
10. 加密后: 45daebacc8ff32dfd20b7c2596354351f727f1a73bcf664759f9162a31e31c72dcff85f97c98da530c4c3d8b76ca63632f8a1c8953fb7c7afd6d2ddae1626395
11. [83, 111, 109, 110, 117, 115]
12. 解密后: Somnus
13. 私钥签名——公钥验证签名
14. 签名:
15. GfLuZt88KdtRoTL7nJoeoRYGW0Lqu9eV4o9J8OVzH9jbHHGa/ZZDlCAjqS1jwkMYaXrut+W2a8v867mZDvQJtw==
16. 状态:true



    简要总结一下,使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互!



类似数字签名,数字信封是这样描述的: 



数字信封

 


  数字信封用加密技术来保证只有特定的收信人才能阅读信的内容。 


流程: 


    信息发送方采用对称密钥来加密信息,然后再用接收方的公钥来加密此对称密钥(这部分称为数字信封),再将它和信息一起发送给接收方;接收方先用相应的私钥打开数字信封,得到对称密钥,然后使用对称密钥再解开信息。