Java 加解密技术系列之 RSA

  • 概念
  • 工作流程
  • RSA
  • 代码实现
  • 加解密结果
  • 结束语


离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版、上线,又是新项目太紧,具体的就不多说了,想听我吐槽的小伙伴,
可以私信给我(*^__^*)
。上一篇文章,已经把对称加密的算法讲完了。从今天开始,要说说非对称加密了。因为,非对称加密真的是太重要了,我们的日常生活中,都离不开非对称加密。
概念

在说 RSA 之前,首先聊聊什么是非对称加密。在讲对称加密的时候,就曾经说过,对称加密算法在加密和解密时使用的是同一个秘钥,加解密双方必须使用同一个密钥才能进行正常的沟通。而非对称加密则不然,非对称加密算法需要两个密钥来进行加密和解密,分别是公钥和私钥。
需要注意的一点,这个公钥和私钥必须是一对的,如果用公钥对数据进行加密,那么只有使用对应的私钥才能解密,反之亦然。由于加密和解密使用的是两个不同的密钥,因此,这种算法叫做非对称加密算法。

工作过程

如下图,甲乙之间使用非对称加密的方式传输数据。
在非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。今天主要是介绍 RSA ,至于其他的算法,后续会选择几个进行介绍。

RSA

其实,在早在 1978 年的时候,RSA就已经出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。其原理就如上面的工作过程所述。
RSA 算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

代码实现

下面来看一下具体的代码实现。
  1. import com.google.common.collect.Maps;
  2. import sun.misc.BASE64Decoder;
  3. import sun.misc.BASE64Encoder;
  4.  
  5. import javax.crypto.Cipher;
  6. import java.security.*;
  7. import java.security.interfaces.RSAPrivateKey;
  8. import java.security.interfaces.RSAPublicKey;
  9. import java.security.spec.PKCS8EncodedKeySpec;
  10. import java.security.spec.X509EncodedKeySpec;
  11. import java.util.Map;
  12.  
  13. /**
  14. * Created by xiang.li on 2015/3/3.
  15. * RSA 加解密工具类
  16. */
  17. public class RSA {
  18. /**
  19. * 定义加密方式
  20. */
  21. private final static String KEY_RSA = "RSA";
  22. /**
  23. * 定义签名算法
  24. */
  25. private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
  26. /**
  27. * 定义公钥算法
  28. */
  29. private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
  30. /**
  31. * 定义私钥算法
  32. */
  33. private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey";
  34.  
  35. /**
  36. * 初始化密钥
  37. * @return
  38. */
  39. public static Map<String, Object> init() {
  40. Map<String, Object> map = null;
  41. try {
  42. KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
  43. generator.initialize(1024);
  44. KeyPair keyPair = generator.generateKeyPair();
  45. // 公钥
  46. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  47. // 私钥
  48. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  49. // 将密钥封装为map
  50. map = Maps.newHashMap();
  51. map.put(KEY_RSA_PUBLICKEY, publicKey);
  52. map.put(KEY_RSA_PRIVATEKEY, privateKey);
  53. } catch (NoSuchAlgorithmException e) {
  54. e.printStackTrace();
  55. }
  56. return map;
  57. }
  58.  
  59. /**
  60. * 用私钥对信息生成数字签名
  61. * @param data 加密数据
  62. * @param privateKey 私钥
  63. * @return
  64. */
  65. public static String sign(byte[] data, String privateKey) {
  66. String str = "";
  67. try {
  68. // 解密由base64编码的私钥
  69. byte[] bytes = decryptBase64(privateKey);
  70. // 构造PKCS8EncodedKeySpec对象
  71. PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
  72. // 指定的加密算法
  73. KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
  74. // 取私钥对象
  75. PrivateKey key = factory.generatePrivate(pkcs);
  76. // 用私钥对信息生成数字签名
  77. Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
  78. signature.initSign(key);
  79. signature.update(data);
  80. str = encryptBase64(signature.sign());
  81. } catch (Exception e) {
  82. e.printStackTrace();
  83. }
  84. return str;
  85. }
  86.  
  87. /**
  88. * 校验数字签名
  89. * @param data 加密数据
  90. * @param publicKey 公钥
  91. * @param sign 数字签名
  92. * @return 校验成功返回true,失败返回false
  93. */
  94. public static boolean verify(byte[] data, String publicKey, String sign) {
  95. boolean flag = false;
  96. try {
  97. // 解密由base64编码的公钥
  98. byte[] bytes = decryptBase64(publicKey);
  99. // 构造X509EncodedKeySpec对象
  100. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
  101. // 指定的加密算法
  102. KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
  103. // 取公钥对象
  104. PublicKey key = factory.generatePublic(keySpec);
  105. // 用公钥验证数字签名
  106. Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
  107. signature.initVerify(key);
  108. signature.update(data);
  109. flag = signature.verify(decryptBase64(sign));
  110. } catch (Exception e) {
  111. e.printStackTrace();
  112. }
  113. return flag;
  114. }
  115.  
  116. /**
  117. * 私钥解密
  118. * @param data 加密数据
  119. * @param key 私钥
  120. * @return
  121. */
  122. public static byte[] decryptByPrivateKey(byte[] data, String key) {
  123. byte[] result = null;
  124. try {
  125. // 对私钥解密
  126. byte[] bytes = decryptBase64(key);
  127. // 取得私钥
  128. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
  129. KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
  130. PrivateKey privateKey = factory.generatePrivate(keySpec);
  131. // 对数据解密
  132. Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
  133. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  134. result = cipher.doFinal(data);
  135. } catch (Exception e) {
  136. e.printStackTrace();
  137. }
  138. return result;
  139. }
  140.  
  141. /**
  142. * 私钥解密
  143. * @param data 加密数据
  144. * @param key 公钥
  145. * @return
  146. */
  147. public static byte[] decryptByPublicKey(byte[] data, String key) {
  148. byte[] result = null;
  149. try {
  150. // 对公钥解密
  151. byte[] bytes = decryptBase64(key);
  152. // 取得公钥
  153. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
  154. KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
  155. PublicKey publicKey = factory.generatePublic(keySpec);
  156. // 对数据解密
  157. Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
  158. cipher.init(Cipher.DECRYPT_MODE, publicKey);
  159. result = cipher.doFinal(data);
  160. } catch (Exception e) {
  161. e.printStackTrace();
  162. }
  163. return result;
  164. }
  165.  
  166. /**
  167. * 公钥加密
  168. * @param data 待加密数据
  169. * @param key 公钥
  170. * @return
  171. */
  172. public static byte[] encryptByPublicKey(byte[] data, String key) {
  173. byte[] result = null;
  174. try {
  175. byte[] bytes = decryptBase64(key);
  176. // 取得公钥
  177. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
  178. KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
  179. PublicKey publicKey = factory.generatePublic(keySpec);
  180. // 对数据加密
  181. Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
  182. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  183. result = cipher.doFinal(data);
  184. } catch (Exception e) {
  185. e.printStackTrace();
  186. }
  187. return result;
  188. }
  189.  
  190. /**
  191. * 私钥加密
  192. * @param data 待加密数据
  193. * @param key 私钥
  194. * @return
  195. */
  196. public static byte[] encryptByPrivateKey(byte[] data, String key) {
  197. byte[] result = null;
  198. try {
  199. byte[] bytes = decryptBase64(key);
  200. // 取得私钥
  201. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
  202. KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
  203. PrivateKey privateKey = factory.generatePrivate(keySpec);
  204. // 对数据加密
  205. Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
  206. cipher.init(Cipher.ENCRYPT_MODE, privateKey);
  207. result = cipher.doFinal(data);
  208. } catch (Exception e) {
  209. e.printStackTrace();
  210. }
  211. return result;
  212. }
  213.  
  214. /**
  215. * 获取公钥
  216. * @param map
  217. * @return
  218. */
  219. public static String getPublicKey(Map<String, Object> map) {
  220. String str = "";
  221. try {
  222. Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
  223. str = encryptBase64(key.getEncoded());
  224. } catch (Exception e) {
  225. e.printStackTrace();
  226. }
  227. return str;
  228. }
  229.  
  230. /**
  231. * 获取私钥
  232. * @param map
  233. * @return
  234. */
  235. public static String getPrivateKey(Map<String, Object> map) {
  236. String str = "";
  237. try {
  238. Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
  239. str = encryptBase64(key.getEncoded());
  240. } catch (Exception e) {
  241. e.printStackTrace();
  242. }
  243. return str;
  244. }
  245.  
  246. /**
  247. * BASE64 解密
  248. * @param key 需要解密的字符串
  249. * @return 字节数组
  250. * @throws Exception
  251. */
  252. public static byte[] decryptBase64(String key) throws Exception {
  253. return (new BASE64Decoder()).decodeBuffer(key);
  254. }
  255.  
  256. /**
  257. * BASE64 加密
  258. * @param key 需要加密的字节数组
  259. * @return 字符串
  260. * @throws Exception
  261. */
  262. public static String encryptBase64(byte[] key) throws Exception {
  263. return (new BASE64Encoder()).encodeBuffer(key);
  264. }
  265.  
  266. /**
  267. * 测试方法
  268. * @param args
  269. */
  270. public static void main(String[] args) {
  271. String privateKey = "";
  272. String publicKey = "";
  273. // 生成公钥私钥
  274. Map<String, Object> map = init();
  275. publicKey = getPublicKey(map);
  276. privateKey = getPrivateKey(map);
  277. System.out.println("公钥: \n\r" + publicKey);
  278. System.out.println("私钥: \n\r" + privateKey);
  279. System.out.println("公钥加密--------私钥解密");
  280. String word = "你好,世界!";
  281. byte[] encWord = encryptByPublicKey(word.getBytes(), publicKey);
  282. String decWord = new String(decryptByPrivateKey(encWord, privateKey));
  283. System.out.println("加密前: " + word + "\n\r" + "解密后: " + decWord);
  284. System.out.println("私钥加密--------公钥解密");
  285. String english = "Hello, World!";
  286. byte[] encEnglish = encryptByPrivateKey(english.getBytes(), privateKey);
  287. String decEnglish = new String(decryptByPublicKey(encEnglish, publicKey));
  288. System.out.println("加密前: " + english + "\n\r" + "解密后: " + decEnglish);
  289. System.out.println("私钥签名——公钥验证签名");
  290. // 产生签名
  291. String sign = sign(encEnglish, privateKey);
  292. System.out.println("签名:\r" + sign);
  293. // 验证签名
  294. boolean status = verify(encEnglish, publicKey, sign);
  295. System.out.println("状态:\r" + status);
  296. }
  297. }

加解密结果

结束语

其实,看似很复杂的过程,用一句话就可以描述:使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互。
非对称加密算法的出现,就是为了解决只有一把密钥的加解密,只要这一把密钥丢失或者被公开,那么加密数据就很容易被攻击。同时,也正是由于非对称加密算法的出现,才有了后面的数字签名、数字证书等等。
好了,今天就到这吧,下一篇继续非对称加密,至于哪一种,到时候就知道了,这里先保密,(*^__^*) 嘻嘻。

9.Java 加解密技术系列之 RSA的更多相关文章

  1. Java 加解密技术系列文章

    Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列 ...

  2. 10.Java 加解密技术系列之 DH

    Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然 ...

  3. 11.Java 加解密技术系列之 总结

    Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的 ...

  4. 8.Java 加解密技术系列之 PBE

    Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认 ...

  5. 7.java 加解密技术系列之 AES

    java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原 ...

  6. 6. Java 加解密技术系列之 3DES

    Java 加解密技术系列之 3DES 序 背景 概念 原理 代码实现 结束语 序 上一篇文章讲的是对称加密算法 — — DES,这篇文章打算在 DES 的基础上,继续多讲一点,也就是 3 重 DES ...

  7. 5.Java 加解密技术系列之 DES

    Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比 ...

  8. 4.Java 加解密技术系列之 HMAC

    Java 加解密技术系列之 HMAC 序 背景 正文 代码 结束语 序 上一篇文章中简单的介绍了第二种单向加密算法 — —SHA,同时也给出了 SHA-1 的 Java 代码.有这方面需求的童鞋可以去 ...

  9. 3.Java 加解密技术系列之 SHA

    Java 加解密技术系列之 SHA 序 背景 正文 SHA-1 与 MD5 的比较 代码实现 结束语 序 上一篇文章中介绍了基本的单向加密算法 — — MD5,也大致的说了说它实现的原理.这篇文章继续 ...

随机推荐

  1. JavaScript Break 和 Continue 语句

    1.break:终止本层循坏,继续执行本次循坏后面的语句: 当循坏有多层时,break只会跳过一层循坏 2.continue:跳过本次循坏,继续执行下次循坏 对于for循环,continue执行后,继 ...

  2. selenium实例:unittest框架+PO开发模式

    这是<selenium2+python学习总结>的升级版. 1.         项目结构 2.         项目代码 1)         globalparameter.py # ...

  3. sqlplus连接oracle问题

    第一次在自己电脑上连接远端数据库,尝试了一上午居然还没成功,后来在网上找了一堆的方法终于是连接上了    -_-!! 总结一下:简单操作:一步到位 我主要是用的oracle 11g的数据库,sqlpl ...

  4. ROS使用常见问题

    1.Q:查看ros版本 A:先在终端输入roscore,打开新终端,再输入,rosparam list,再输入rosparam get /rosdistro,就能得到版本. 2.Q:运行命令$ ros ...

  5. 1020. Tree Traversals

    Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and i ...

  6. 0-创建scott示例数据

    CREATE TABLE dept (  deptno INT PRIMARY KEY,  dname VARCHAR(14),  loc VARCHAR(13) );   INSERT INTO d ...

  7. sass入门学习篇(二)

    从语法开始但是语法也不是一两句的事情,首先看基本的导入,使用 一,sass有两种后缀名文件:一种后缀名为sass,不使用大括号和分号:另一种就是我们这里使用的scss文件,建议scss. 二,导入 使 ...

  8. JS + HTml 时钟代码实现

    JS+ Html 画布实现的时钟效果图: 闲来无聊做了一个网页的时钟,效果模拟传统时钟的运行方式, 运用了html 的画布实现指针,背景图片引用了网络图片. 具体原理: 首先将时钟分为四个不同区域,对 ...

  9. 【整理】hash算法原理及常见函数

    简介 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.        散列表 ...

  10. JAVA 继承中的this和super

    学习java时看了不少尚学堂马士兵的视频,还是挺喜欢马士兵的讲课步骤的,二话不说,先做实例,看到的结果才是最实际的,理论神马的全是浮云.只有在实际操作过程中体会理论,在实际操作过程中升华理论才是最关键 ...