用RSA非对称加密方式实现。后台生成rsa密钥对,然后在页面设置rsa公钥,提交时用公钥加密密码,生成的密文传到后台,后台再用私钥解密,获取密码明文。
这样客户端只需要知道rsa加密方式和公钥,前台不知道私钥是无法解密的,此解决方案还是相对比较安全的。
需要到http://www.bouncycastle.org下载bcprov-jdk16-140.jar文件。
缺陷:
由于进行的都是大数计算,使得RSA最快的情况也比DES慢上100倍,无论 是软件还是硬件实现。所以
一般来说只用于少 量数据 加密。
下面我们就来一个实际的例子:
1、前端加密需要引入Barrett.js、BigInt.js和RSA.js。
1. <script src="/rsa/RSA.js" type="text/javascript"></script>
2. <script src="/rsa/BigInt.js" type="text/javascript"></script>
3. <script src="/rsa/Barrett.js" type="text/javascript"></script>
复制代码
2、前端加密代码:
1. encryptedString : (function(paramStr, rsaKey){
2. setMaxDigits(130);
3. //第一个参数为加密指数、第二个参数为解密参数、第三个参数为加密系数
4. key = new RSAKeyPair("10001", "", rsaKey);
5. //返回加密后的字符串
6. return encryptedString(key, encodeURIComponent(paramStr));
7. })
复制代码
其中的加密系数可以自定义,这里为:8246a46f44fc4d961e139fd70f4787d272d374532f4d2d9b7cbaad6a15a8c1301319aa6b3f30413b859351c71938aec516fa7147b69168b195e81df46b6bed7950cf3a1c719d42175f73d7c97a85d7d20a9e83688b92f05b3059bb2ff75cd7190a042cd2db97ebc2ab4da366f2a7085556ed613b5a39c9fdd2bb2595d1dc23b5
3、后台RSA加密解密方法如下:
1. import java.io.ByteArrayOutputStream;
2. import java.io.FileInputStream;
3. import java.io.FileOutputStream;
4. import java.io.ObjectInputStream;
5. import java.io.ObjectOutputStream;
6. import java.math.BigInteger;
7. import java.security.KeyFactory;
8. import java.security.KeyPair;
9. import java.security.KeyPairGenerator;
10. import java.security.NoSuchAlgorithmException;
11. import java.security.PrivateKey;
12. import java.security.PublicKey;
13. import java.security.SecureRandom;
14. import java.security.interfaces.RSAPrivateKey;
15. import java.security.interfaces.RSAPublicKey;
16. import java.security.spec.InvalidKeySpecException;
17. import java.security.spec.RSAPrivateKeySpec;
18. import java.security.spec.RSAPublicKeySpec;
19.
20. import javax.crypto.Cipher;
21.
22. import org.apache.commons.lang.StringUtils;
23.
24. import com.jd.uwp.common.Constants;
25.
26. /**
27. * RSA 工具类。提供加密,解密,生成密钥对等方法。
28. * 需要bcprov-jdk16-140.jar包。
29. *
30. */
31. public class RSAUtil {
32.
33. private static String RSAKeyStore = "RSAKey.txt";
34.
35. /**
36. * * 生成密钥对 *
37. * @return KeyPair *
38. * @throws EncryptException
39. */
40. public static KeyPair generateKeyPair(String basePath) throws Exception {
41. try {
42. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
43. new org.bouncycastle.jce.provider.BouncyCastleProvider());
44. //大小
45. final int KEY_SIZE = 1024;
46. keyPairGen.initialize(KEY_SIZE, new SecureRandom());
47. KeyPair keyPair = keyPairGen.generateKeyPair();
48. saveKeyPair(keyPair, basePath);
49. return keyPair;
50. } catch (Exception e) {
51. throw new Exception(e.getMessage());
52. }
53. }
54.
55. /**
56. * 获取密钥对
57. * @return
58. * @throws Exception
59. */
60. public static KeyPair getKeyPair(String basePath) throws Exception {
61. FileInputStream fis = new FileInputStream(StringUtils.isNotBlank(basePath) ? (basePath + RSAKeyStore) : RSAKeyStore);
62. ObjectInputStream oos = new ObjectInputStream(fis);
63. KeyPair kp = (KeyPair) oos.readObject();
64. oos.close();
65. fis.close();
66. return kp;
67. }
68.
69. /**
70. * 保存密钥
71. * @param kp
72. * @throws Exception
73. */
74. public static void saveKeyPair(KeyPair kp, String basePath) throws Exception {
75. FileOutputStream fos = new FileOutputStream(StringUtils.isNotBlank(basePath) ? (basePath + RSAKeyStore) : RSAKeyStore);
76. ObjectOutputStream oos = new ObjectOutputStream(fos);
77. // 生成密钥
78. oos.writeObject(kp);
79. oos.close();
80. fos.close();
81. }
82.
83. /**
84. * * 生成公钥 *
85. * @param modulus *
86. * @param publicExponent *
87. * @return RSAPublicKey *
88. * @throws Exception
89. */
90. public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
91. byte[] publicExponent) throws Exception {
92. KeyFactory keyFac = null;
93. try {
94. keyFac = KeyFactory.getInstance("RSA",
95. new org.bouncycastle.jce.provider.BouncyCastleProvider());
96. } catch (NoSuchAlgorithmException ex) {
97. throw new Exception(ex.getMessage());
98. }
99. RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
100. modulus), new BigInteger(publicExponent));
101. try {
102. return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
103. } catch (InvalidKeySpecException ex) {
104. throw new Exception(ex.getMessage());
105. }
106. }
107.
108. /**
109. * * 生成私钥 *
110. * @param modulus *
111. * @param privateExponent *
112. * @return RSAPrivateKey *
113. * @throws Exception
114. */
115. public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
116. byte[] privateExponent) throws Exception {
117. KeyFactory keyFac = null;
118. try {
119. keyFac = KeyFactory.getInstance("RSA",
120. new org.bouncycastle.jce.provider.BouncyCastleProvider());
121. } catch (NoSuchAlgorithmException ex) {
122. throw new Exception(ex.getMessage());
123. }
124. RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
125. modulus), new BigInteger(privateExponent));
126. try {
127. return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
128. } catch (InvalidKeySpecException ex) {
129. throw new Exception(ex.getMessage());
130. }
131. }
132.
133. /**
134. * * 加密 *
135. * @param key
136. * 加密的密钥 *
137. * @param data
138. * 待加密的明文数据 *
139. * @return 加密后的数据 *
140. * @throws Exception
141. */
142. public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
143. try {
144. Cipher cipher = Cipher.getInstance("RSA",
145. new org.bouncycastle.jce.provider.BouncyCastleProvider());
146. cipher.init(Cipher.ENCRYPT_MODE, pk);
147. // 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
148. int blockSize = cipher.getBlockSize();
149. // 加密块大小为127
150. // byte,加密后为128个byte;因此共有2个加密块,第一个127
151. // byte第二个为1个byte
152. int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
153. int leavedSize = data.length % blockSize;
154. int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;
155. byte[] raw = new byte[outputSize * blocksSize];
156. int i = 0;
157. while (data.length - i * blockSize > 0) {
158. if (data.length - i * blockSize > blockSize) {
159. cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
160. } else {
161. cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
162. }
163. i++;
164. }
165. return raw;
166. } catch (Exception e) {
167. throw new Exception(e.getMessage());
168. }
169. }
170.
171. /**
172. * * 解密 *
173. *
174. * @param key
175. * 解密的密钥 *
176. * @param raw
177. * 已经加密的数据 *
178. * @return 解密后的明文 *
179. * @throws Exception
180. */
181. @SuppressWarnings("static-access")
182. public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
183. try {
184. Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
185. cipher.init(cipher.DECRYPT_MODE, pk);
186. int blockSize = cipher.getBlockSize();
187. ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
188. int j = 0;
189. while (raw.length - j * blockSize > 0) {
190. bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
191. j++;
192. }
193. return bout.toByteArray();
194. } catch (Exception e) {
195. throw new Exception(e.getMessage());
196. }
197. }
198.
199. /**
200. * 解密方法
201. * paramStr ->密文
202. * basePath ->RSAKey.txt所在的文件夹路径
203. **/
204. public static String decryptStr(String paramStr, String basePath) throws Exception{
205. byte[] en_result = new BigInteger(paramStr, 16).toByteArray();
206. byte[] de_result = decrypt(getKeyPair(basePath).getPrivate(), en_result);
207. StringBuffer sb = new StringBuffer();
208. sb.append(new String(de_result));
209. //返回解密的字符串
210. return sb.reverse().toString();
211. }
212. }
213.
复制代码
4、前端提交到后端解密调用:
1. //前端 表单提交
2. $.ajax({
3. url : contextPath + "test.action",
4. //加密传输
5. data : {pwd:encryptedString ($("#pwd").val(), "adasdasdasdasdadsasdasdasdasd")},
6. type : "post",
7. datatype : "json",
8. success : function(retData){
9. }
10. });
11.
12. //后端解密代码
13. RSAUtil.decryptStr(paramMap.getString("pwd"), request.getSession().getServletContext().getRealPath("/"));
复制代码