RSA加解密

た 入场券 2022-10-21 03:53 397阅读 0赞

一:RSA加解密背景

  1. RSA是目前使用最广泛的公钥密码体制之一。它是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
  2. RSA算法的安全性基于RSA问题的困难性,也就是基于大整数因子分解的困难性上。但是RSA问题不会比因子分解问题更加困难,也就是说,在没有解决因子分解问题的情况下可能解决RSA问题,因此RSA算法并不是完全基于大整数因子分解的困难性上的。

二:RSA算法描述

1:RSA产生公私钥对

具体实例讲解如何生成密钥对

  • 1.随机选择两个不相等的质数p和q。
    alice选择了61和53。(实际应用中,这两个质数越大,就越难破解。)
  • 2.计算p和q的乘积n。
    n = 61×53 = 3233
    n的长度就是密钥长度。3233写成二进制是110010100001,一共有12位,所以这个密钥就是12位。实际应用中,RSA密钥一般是1024位,重要场合则为2048位。
  • 3.计算n的欧拉函数φ(n)。称作L
    根据公式φ(n) = (p-1)(q-1)
    alice算出φ(3233)等于60×52,即3120。
  • 4.随机选择一个整数e,也就是公钥当中用来加密的那个数字
    条件是1< e < φ(n),且e与φ(n) 互质。
    alice就在1到3120之间,随机选择了17。(实际应用中,常常选择65537。)
  • 5.计算e对于φ(n)的模反元素d。也就是密钥当中用来解密的那个数字
    所谓”模反元素”就是指有一个整数d,可以使得ed被φ(n)除的余数为1。ed ≡ 1 (mod φ(n))
    alice找到了2753,即17*2753 mode 3120 = 1
  • 6.将n和e封装成公钥,n和d封装成私钥。
    在alice的例子中,n=3233,e=17,d=2753,所以公钥就是 (3233,17),私钥就是(3233, 2753)。

2:RSA加密

首先对明文进行比特串分组,使得每个分组对应的十进制数小于n,然后依次对每个分组m做一次加密,所有分组的密文构成的序列就是原始消息的加密结果,即m满足0<=m<n,则加密算法为:
c≡ m^e mod n; c为密文,且0<=c<n。

3:RSA解密

对于密文0<=c<n,解密算法为:
m≡ c^d mod n;

4:RSA签名验证

RSA密码体制既可以用于加密又可以用于数字签名。下面介绍RSA数字签名的功能。
已知公钥(e,n),私钥d

  • 1.对于消息m签名为:sign ≡ m ^d mod n
  • 2.验证:对于消息签名对(m,sign),如果m ≡ sign ^e mod n,则sign是m的有效签名

本质就是一个欧拉算法

三:RSA公开密钥密码体制

所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。

根据密钥的使用方法,可以将密码分为对称密码和公钥密码

对称密码:加密和解密使用同一种密钥的方式

公钥密码:加密和解密使用不同的密码的方式,因此公钥密码通常也称为非对称密码。

四:rsa加解密的内容超长

实际使用RSA加解密算法通常有两种不同的方式

一种是使用对称密钥(比如AES/DES等加解密方法)加密数据,然后使用非对称密钥(RSA加解密密钥)加密对称密钥;

另一种是直接使用非对称密钥加密数据。第一种方式安全性高,复杂度也高,不存在加密数据长度限制问题,第二种方式安全性差一些,复杂度低,但是存在加密数据限制问题(即使用非对称密钥加密数据时,一次加密的数据长度是(密钥长度/8-11))。

目前双方约定的方式为第二种方式,而对应于本次抛错的密钥,key长度为1024位,1024/8 - 11 = 117,所以一次加密内容不能超过117bytes。另一个密钥没有问题,因为key的长度为2048位,2048/8 - 11 = 245,一次加密内容不能超过245bytes。而分段加密代码中用128为单位分段,从而使得一个密钥报错,另一个不报错。

五:代码实现

pom依赖

  1. <dependency>
  2. <groupId>commons-codec</groupId>
  3. <artifactId>commons-codec</artifactId>
  4. <version>1.13</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>commons-io</groupId>
  8. <artifactId>commons-io</artifactId>
  9. <version>2.4</version>
  10. </dependency>
  11. RSAUtils实体类:
  12. package rsa;
  13. import org.apache.commons.codec.binary.Base64;
  14. import org.apache.commons.io.IOUtils;
  15. import javax.crypto.Cipher;
  16. import java.io.ByteArrayOutputStream;
  17. import java.security.*;
  18. import java.security.interfaces.RSAPrivateKey;
  19. import java.security.interfaces.RSAPublicKey;
  20. import java.security.spec.InvalidKeySpecException;
  21. import java.security.spec.PKCS8EncodedKeySpec;
  22. import java.security.spec.X509EncodedKeySpec;
  23. import java.util.HashMap;
  24. import java.util.Map;
  25. /**
  26. * @author lizhangyu
  27. * @date 2021/5/3 21:07
  28. */
  29. public class RSAUtils {
  30. public static final String CHARSET = "UTF-8";
  31. public static final String RSA_ALGORITHM = "RSA";
  32. /**
  33. * 生成公钥和私钥
  34. * @param keySize
  35. * @return
  36. */
  37. public static Map<String, String> createKeys(int keySize){
  38. //为RSA算法创建一个KeyPairGenerator对象
  39. KeyPairGenerator kpg;
  40. try{
  41. kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
  42. }catch(NoSuchAlgorithmException e){
  43. throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
  44. }
  45. //初始化KeyPairGenerator对象,密钥长度
  46. kpg.initialize(keySize);
  47. //生成密匙对
  48. KeyPair keyPair = kpg.generateKeyPair();
  49. //得到公钥
  50. Key publicKey = keyPair.getPublic();
  51. String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
  52. //得到私钥
  53. Key privateKey = keyPair.getPrivate();
  54. String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
  55. Map<String, String> keyPairMap = new HashMap<String, String>();
  56. keyPairMap.put("publicKey", publicKeyStr);
  57. keyPairMap.put("privateKey", privateKeyStr);
  58. return keyPairMap;
  59. }
  60. /**
  61. * 得到公钥
  62. * @param publicKey 密钥字符串(经过base64编码)
  63. * @throws Exception
  64. */
  65. public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
  66. //通过X509编码的Key指令获得公钥对象
  67. KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
  68. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
  69. RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
  70. return key;
  71. }
  72. /**
  73. * 得到私钥
  74. * @param privateKey 密钥字符串(经过base64编码)
  75. * @throws Exception
  76. */
  77. public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
  78. //通过PKCS#8编码的Key指令获得私钥对象
  79. KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
  80. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
  81. RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
  82. return key;
  83. }
  84. /**
  85. * 公钥加密
  86. * @param data
  87. * @param publicKey
  88. * @return
  89. */
  90. public static String publicEncrypt(String data, RSAPublicKey publicKey){
  91. try{
  92. Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
  93. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  94. return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
  95. }catch(Exception e){
  96. throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
  97. }
  98. }
  99. /**
  100. * 私钥解密
  101. * @param data
  102. * @param privateKey
  103. * @return
  104. */
  105. public static String privateDecrypt(String data, RSAPrivateKey privateKey){
  106. try{
  107. Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
  108. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  109. return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
  110. }catch(Exception e){
  111. throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
  112. }
  113. }
  114. /**
  115. * 私钥加密
  116. * @param data
  117. * @param privateKey
  118. * @return
  119. */
  120. public static String privateEncrypt(String data, RSAPrivateKey privateKey){
  121. try{
  122. Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
  123. cipher.init(Cipher.ENCRYPT_MODE, privateKey);
  124. return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
  125. }catch(Exception e){
  126. throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
  127. }
  128. }
  129. /**
  130. * 公钥解密
  131. * @param data
  132. * @param publicKey
  133. * @return
  134. */
  135. public static String publicDecrypt(String data, RSAPublicKey publicKey){
  136. try{
  137. Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
  138. cipher.init(Cipher.DECRYPT_MODE, publicKey);
  139. return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
  140. }catch(Exception e){
  141. throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
  142. }
  143. }
  144. /**
  145. * 分段加解密
  146. * @param cipher
  147. * @param opmode
  148. * @param datas
  149. * @param keySize
  150. * @return
  151. */
  152. private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
  153. int maxBlock = 0;
  154. if(opmode == Cipher.DECRYPT_MODE){
  155. maxBlock = keySize / 8;
  156. }else{
  157. maxBlock = keySize / 8 - 11;
  158. }
  159. ByteArrayOutputStream
  160. out = new ByteArrayOutputStream();
  161. int offSet = 0;
  162. byte[] buff;
  163. int i = 0;
  164. try{
  165. while(datas.length > offSet){
  166. if(datas.length-offSet > maxBlock){
  167. buff = cipher.doFinal(datas, offSet, maxBlock);
  168. }else{
  169. buff = cipher.doFinal(datas, offSet, datas.length-offSet);
  170. }
  171. out.write(buff, 0, buff.length);
  172. i++;
  173. offSet = i * maxBlock;
  174. }
  175. }catch(Exception e){
  176. throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
  177. }
  178. byte[] resultDatas = out.toByteArray();
  179. IOUtils.closeQuietly(out);
  180. return resultDatas;
  181. }
  182. public static void main (String[] args) throws Exception {
  183. Map<String, String> keyMap = RSAUtils.createKeys(1024);
  184. String publicKey = keyMap.get("publicKey");
  185. String privateKey = keyMap.get("privateKey");
  186. System.out.println("公钥: \n\r" + publicKey);
  187. System.out.println("私钥: \n\r" + privateKey);
  188. System.out.println("公钥加密——私钥解密");
  189. String str = "code_cayden";
  190. System.out.println("\r明文:\r\n" + str);
  191. System.out.println("\r明文大小:\r\n" + str.getBytes().length);
  192. String encodedData = RSAUtils.publicEncrypt(str, RSAUtils.getPublicKey(publicKey));
  193. System.out.println("密文:\r\n" + encodedData);
  194. String decodedData = RSAUtils.privateDecrypt(encodedData, RSAUtils.getPrivateKey(privateKey));
  195. System.out.println("解密后文字: \r\n" + decodedData);
  196. }
  197. }

运行结果:

  1. 公钥:
  2. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCWRAc8LEHSZ9uW-IUPX0HeMfO_hADL5_Sdo874ZZQ3XBkA4m28Vz5pE_8oRZrwJNAre7vaBn2VGdxmNpRtwnnWTA57OXoMYVzxchx6Xfqnf5S87qt9BKJh3gaWn_m4ZB8-klNddQcRjesolNA8IvgqrtigmD5lLo0_ORsz3_UMjwIDAQAB
  3. 私钥:
  4. MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJZEBzwsQdJn25b4hQ9fQd4x87-EAMvn9J2jzvhllDdcGQDibbxXPmkT_yhFmvAk0Ct7u9oGfZUZ3GY2lG3CedZMDns5egxhXPFyHHpd-qd_lLzuq30EomHeBpaf-bhkHz6SU111BxGN6yiU0Dwi-Cqu2KCYPmUujT85GzPf9QyPAgMBAAECgYAt9us7pdIQmYJbQPP6ysmsPR1xdOCFfxOdcPErnG7lLD_dvGWS2iEWJW7Ek94cHTasRnIk9B1QEZQQlBt9I6L-yKiGows7o-a0K-MD2sXW7h3cpQJkgU8uagFt59rAPJX3QJ_Nh0jETg18e5cucuA12hZchNjAsAB8h7ALPhm0AQJBANnNSrW3NOT1Q6BIOjezbboGVd9VNzmWPYEYQYP1BPJsTVIgD-h8HN8IEb_Umjw6UzSHIX6I99JKaL5GlocRto8CQQCwnowReKo28dLlanegBLktr3eV_v72Og2-tnpHfeZXTQOu4JBv5VwcD3VD2zV7vwUgcL_rEbjLvaph_5LjAkoBAkEAxioOy37BVYAB45dTwNI0B4k0IFr8QBz-ILLdCR6pPZhkUVByqOgjrJk-7PaWzi2S_rvkMaiVMnQZEOZQltv66QJAb3-X00vGwSsGxZfh7x4sPSAhsYqqMI1TsgsGxO1BJenTomnYJRu5e2ly0SSo7fcYaHNlZSPp8o1I69bpRvBiAQJBANGx7ESEJWuYflIq6oyCl8i-yfclN7u9VaTie6Lilc4PP_B79qfC2PTiq29QdHJGhEAij7TmbMzfNG76zGeref4
  5. 公钥加密——私钥解密
  6. 明文:
  7. code_cayden
  8. 明文大小:
  9. 11
  10. 密文:
  11. i-ymiXtQsUiXssHwE3oldfi1cKP0cgDsBEakKOktlIkD5nzrOlk0WFC_mf5-CM8Jz1doPvI27jj8LUb4BrSrHkgH4PIyVjyxLRGFx-9ml4XaDgjfv7pIoczq2Nr3Fb3jPsKrcksW5dhjfIRik8iiupIjqi2cIS0nC03InnbQK60
  12. 解密后文字:
  13. code_cayden
  14. Process finished with exit code 0

总结:RSA是一个非对称加密,但是加解密过程中存在长度限制,需要分段加解密,同时在加解密的过程中存在效率问题。

发表评论

表情:
评论列表 (有 0 条评论,397人围观)

还没有评论,来说两句吧...

相关阅读

    相关 RSA解密

    一:RSA加解密背景 RSA是目前使用最广泛的公钥密码体制之一。它是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦

    相关 RSA解密算法

    一、什么是RSA   RSA[公开密钥密码体制][Link 1]。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不