RSA加密解密与加签验签

  RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年7月首次在美国公布,当时他们三人都在麻省理工学院工作实习。RSA就是他们三人姓氏开头字母拼在一起组成的。

  RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。

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

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

  基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可以在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。

  RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,截止2017年被普遍认为是最优秀的公钥方案之一。

  SET(Secure Electronic Transaction)协议中要求CA采用2048bits长的密钥,其他实体使用1024比特的密钥。RSA密钥长度随着保密级别提高,增加很快。

  RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。

  我们接下来看下Java中如何实现RSA加密解密与加签验签。我们先来看RSA加密解密。  

 1 import javax.crypto.BadPaddingException;
 2 import javax.crypto.Cipher;
 3 import javax.crypto.IllegalBlockSizeException;
 4 import javax.crypto.NoSuchPaddingException;
 5 import java.security.*;
 6 import java.util.Base64;
 7 /**
 8  * RSA加密解密操作步骤
 9  */
10 public class Test1 {
11     public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
12         //先给出一个待加密的字符串
13         String data="青青子衿,悠悠我心。但为君故,沉吟至今。";
14         //1.构建公私钥匙对
15         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
16         KeyPair keyPair = keyPairGenerator.generateKeyPair();
17         //2.获取钥匙对中的公钥
18         PublicKey publicKey = keyPair.getPublic();
19         //3.获取钥匙对中的私钥
20         PrivateKey privateKey = keyPair.getPrivate();
21         //4.对待加密的数据进行加密
22         Cipher cipher = Cipher.getInstance("RSA");
23         cipher.init(Cipher.ENCRYPT_MODE,publicKey);
24         byte[] bytesEncrypt = cipher.doFinal(data.getBytes());//产生的是乱码,需要用Base64进行转码
25         //5.Base64编码
26         byte[] encodeBase64 = Base64.getEncoder().encode(bytesEncrypt);
27         System.out.println("加密后的数据:"+new String(encodeBase64));
28         //6.在解密时,先对用Base64编码的信息进行解码
29         byte[] bytesDecode = Base64.getDecoder().decode(encodeBase64);
30         //7.解密
31         Cipher cipher2=Cipher.getInstance("RSA");
32         cipher2.init(Cipher.DECRYPT_MODE,privateKey);
33         byte[] bytesDecrypt = cipher2.doFinal(bytesDecode);
34         System.out.println("解密后的数据:"+new String(bytesDecrypt));
35     }
36 }

  公钥和私钥本身存储的信息是乱码,在实际使用中,我们还可以通过Base64将这些乱码编码为可识别的ASCII码,然后将公钥和私钥信息持久化存储到文件中,在以后需要使用时,可以从文件中读取公钥和私钥信息。为此,我们可以写一个RSA的工具类,从一个储存公钥和私钥信息的文件里读取公钥和私钥信息,然后定义获取公钥和私钥的方法,以及加密和解密数据的方法。首先,我们提供一对公私钥信息,假定公钥信息储存在一个名称为rsa_public_key.pem的文件里,信息如下:

-----BEGIN RSA PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDY90KtriCa4KjNe3mgrGGbDB95
8A2byBKf+wOmPmOopP3gGeg7+DFAPNYCC+tL8h2bpUI3IPKOm2Hon8kM/p628i1J
Z7JjopYVZW6JKqA2ImyneeUEK748FXwXTRAAMCTqQG/7a178BGawTdHi6hk+M6UF
lT0EhL6JA8ULKFoiHwIDAQAB
-----BEGIN RSA PUBLIC KEY-----

  假定私钥信息储存在一个名称为rsa_private_key.pem的文件里,信息如下::

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDY90KtriCa4KjNe3mgrGGbDB958A2byBKf+wOmPmOopP3gGeg7
+DFAPNYCC+tL8h2bpUI3IPKOm2Hon8kM/p628i1JZ7JjopYVZW6JKqA2ImyneeUE
K748FXwXTRAAMCTqQG/7a178BGawTdHi6hk+M6UFlT0EhL6JA8ULKFoiHwIDAQAB
AoGBAIJFhF2wLZeQyQoH13Gnzzs/Pi8C+cjNipFQMFLDJyd9WYoTRCOt1DST0pOM
AI2rJCfuRCHBwKHrnhAE0LzirPxkmvyHTIBXIoz3fHiSkIKkUVG04BcgTYpNKWPB
ISlzdhSaw7CnmJjTthTrD5LLPtpqUl350lUYFEHVNR6Ys9JRAkEA9JUEVxzSvQkV
V6hxhbvlxl0mATbPfiNKDBTPdr48dyYdgluAoGfAPf9rmgoCpdEd2hZBIfdy7xdL
LvP7ztb/rQJBAOMYNC/lZLz9A9cDJ5bibrJnmyRG0SAGAzu4ffYdBoGb0kRRKzTe
5jxfRnbiUPQU4GQXhADfikGn2ogRqbtDsnsCQQCJdp+D3n1LJanLJK75PQv9myjb
EdU4zdi2RZP85xrQ1KlNNORsQyO3NLFjWDD4xTmD83IUByGf43WsJBDoxcnZAkA3
i84IARX42/I6fz0JvOzSmmDqKKAyMwZLbz7wGf1jalet+iSVVAgAsFUt8wFWEl0o
XlAdXpAUqxfavGdFtLNNAkABS576xgLcLmyw51f9hoM9RiamLn+WNzoA5TLOZjGI
dZZnX/A8SoFYGoJoN1O0hp5DxDdl+gjW/mH51+gliEIB
-----END RSA PRIVATE KEY-----

  接下来,我们写一个RSAUtil工具类,代码如下:  

  1 import javax.crypto.BadPaddingException;
  2 import javax.crypto.Cipher;
  3 import javax.crypto.IllegalBlockSizeException;
  4 import javax.crypto.NoSuchPaddingException;
  5 import java.io.BufferedReader;
  6 import java.io.FileReader;
  7 import java.io.IOException;
  8 import java.security.*;
  9 import java.security.spec.InvalidKeySpecException;
 10 import java.security.spec.PKCS8EncodedKeySpec;
 11 import java.security.spec.X509EncodedKeySpec;
 12 import java.util.Base64;
 13 /**
 14  * 工具类
 15  */
 16 public class RSAUtil {
 17     /*
 18         读取秘钥数据
 19      */
 20     public static byte[] readKeyDatas(String keyFilePath){
 21         BufferedReader bufferedReader=null;
 22         try{
 23             bufferedReader = new BufferedReader(new FileReader(keyFilePath));
 24             String str=null;
 25             StringBuilder stringBuilder=new StringBuilder();
 26             while ((str=bufferedReader.readLine())!=null){
 27                 if(str.contains("---")){
 28                     continue;
 29                 }
 30                 stringBuilder.append(str);
 31             }
 32             return stringBuilder.toString().getBytes();
 33         }catch (IOException e) {
 34             e.printStackTrace();
 35         }finally {
 36             try {
 37                 bufferedReader.close();
 38             } catch (IOException e) {
 39                 e.printStackTrace();
 40             }
 41         }
 42         return null;
 43     }
 44     /*
 45         生成公钥
 46      */
 47     public static PublicKey getPublicKey(String publicKeyPath){
 48         //1.读取公钥文件,获取公钥数据
 49         byte[] bytesPublicBase64 = readKeyDatas(publicKeyPath);
 50         //2.对读取回来的数据进行Base64解码
 51         byte[] bytesPublic = Base64.getDecoder().decode(bytesPublicBase64);
 52         //3.把解码后的数据,重新封装成一个PublicKey对象
 53         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytesPublic);
 54         KeyFactory keyFactory=null;
 55         try {
 56             keyFactory = KeyFactory.getInstance("RSA");
 57             PublicKey publicKey = keyFactory.generatePublic(keySpec);
 58             return publicKey;
 59         } catch (NoSuchAlgorithmException e) {
 60             e.printStackTrace();
 61         } catch (InvalidKeySpecException e) {
 62             e.printStackTrace();
 63         }
 64         return null;
 65     }
 66     /*
 67         生成私钥
 68      */
 69     public static PrivateKey getPrivateKey(String privateKeyPath){
 70         //1.读取私钥文件,获取私钥数据
 71         byte[] bytesPrivateBase64 = readKeyDatas(privateKeyPath);
 72         //2.对读取回来的数据进行Base64解码
 73         byte[] bytesPrivate = Base64.getDecoder().decode(bytesPrivateBase64);
 74         //3.把解码后的数据,重新封装成一个PrivateKey对象
 75         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytesPrivate);
 76         KeyFactory keyFactory=null;
 77         try {
 78             keyFactory = KeyFactory.getInstance("RSA");
 79             PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
 80             return privateKey;
 81         } catch (NoSuchAlgorithmException e) {
 82             e.printStackTrace();
 83         } catch (InvalidKeySpecException e) {
 84             e.printStackTrace();
 85         }
 86         return null;
 87     }
 88     /*
 89         加密数据
 90      */
 91     public static String encodeData(PublicKey publicKey,String originData){
 92         try {
 93             Cipher cipher = Cipher.getInstance("RSA");
 94             cipher.init(Cipher.ENCRYPT_MODE,publicKey);
 95             byte[] bytesEncrypt = cipher.doFinal(originData.getBytes());
 96             //Base64编码
 97             byte[] bytesEncryptBase64 = Base64.getEncoder().encode(bytesEncrypt);
 98             return new String(bytesEncryptBase64);            
 99         } catch (NoSuchAlgorithmException e) {
100             e.printStackTrace();
101         } catch (NoSuchPaddingException e) {
102             e.printStackTrace();
103         } catch (InvalidKeyException e) {
104             e.printStackTrace();
105         } catch (BadPaddingException e) {
106             e.printStackTrace();
107         } catch (IllegalBlockSizeException e) {
108             e.printStackTrace();
109         }
110         return null;
111     }
112     /*
113         解密数据
114      */
115     public static String decodeData(PrivateKey privateKey,String encodeData){
116         try {
117             //Base64解码
118             byte[] bytesEncrypt = Base64.getDecoder().decode(encodeData);
119             //加密
120             Cipher cipher = Cipher.getInstance("RSA");
121             cipher.init(Cipher.DECRYPT_MODE,privateKey);
122             byte[] bytesDecrypt = cipher.doFinal(bytesEncrypt);
123             return new String(bytesDecrypt);
124         } catch (NoSuchAlgorithmException e) {
125             e.printStackTrace();
126         } catch (NoSuchPaddingException e) {
127             e.printStackTrace();
128         } catch (InvalidKeyException e) {
129             e.printStackTrace();
130         } catch (BadPaddingException e) {
131             e.printStackTrace();
132         } catch (IllegalBlockSizeException e) {
133             e.printStackTrace();
134         }
135         return null;
136     }   
137 }

  这样的话,以后需要使用公钥和私钥,以及加密解密时,调用上述工具类中的相应方法即可。

  最后,我们再来看用RSA如何对数据进行加签验签,具体代码如下:

 1 import java.io.UnsupportedEncodingException;
 2 import java.security.*;
 3 /**
 4  * 加签  验签    签名验证:验证数据的合法来源   即验证数据来源的合法性
 5  * 加签:私钥
 6  * 验签:公钥
 7  */
 8 public class Test2 {
 9     private static String privateKeyPath="储存私钥信息的文件路径";
10     private static String publicKeyPath="储存公钥信息的文件路径";
11     public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
12         String data="验证该数据是否为合法的服务器发送";
13         /**
14          * 加签过程
15          */
16         PrivateKey privateKey = RSAUtil.getPrivateKey(privateKeyPath);
17         Signature signature = Signature.getInstance("Sha1WithRSA");
18         signature.initSign(privateKey);
19         signature.update(data.getBytes("UTF-8"));
20         byte[] signed = signature.sign();
21         /**
22          * 验签过程
23          */
24         PublicKey publicKey = RSAUtil.getPublicKey(publicKeyPath);
25         Signature signature2 = Signature.getInstance("Sha1WithRSA");
26         signature2.initVerify(publicKey);
27         signature2.update(data.getBytes("UTF-8"));
28         boolean verify = signature2.verify(signed);
29         System.out.println("验签结果:"+verify);
30     }    
31 }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenSSL是一个开源的密库,它提供了RSA密、解密、名和验的功能。 对于RSA密和解密,我们可以使用OpenSSL提供的命令行工具或者API来实现。 使用命令行工具,我们可以通过以下命令进行RSA密: openssl rsautl -encrypt -in <input file> -out <output file> -inkey <public key file> -pubin 其中,<input file>是要密的文件,<output file>是密后的文件,<public key file>是存储公钥的文件,-pubin参数表示输入的是公钥。 使用命令行工具,我们可以通过以下命令进行RSA解密: openssl rsautl -decrypt -in <input file> -out <output file> -inkey <private key file> 其中,<input file>是要解密的文件,<output file>是解密后的文件,<private key file>是存储私钥的文件。 对于RSA名和验,我们可以使用以下命令进行名: openssl rsautl -sign -in <input file> -out <output file> -inkey <private key file> 其中,<input file>是要名的文件,<output file>是名后的文件,<private key file>是存储私钥的文件。 使用以下命令进行验: openssl rsautl -verify -in <input file> -out <output file> -inkey <public key file> -pubin 其中,<input file>是要验的文件,<output file>是验后的文件,<public key file>是存储公钥的文件,-pubin参数表示输入的是公钥。 使用OpenSSL的API进行RSA密、解密、名和验的操作也是类似的,我们可以通过调用相应的函数来实现。需要注意的是,API的使用需要在代码中显式引入OpenSSL的头文件和链接OpenSSL的库文件。 总之,OpenSSL提供了便捷的工具和API来实现RSA密、解密、名和验的功能,无论是命令行工具还是API,都可以选择合适的方式进行操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值