Java中使用OpenSSL生成的RSA公私钥进行数据加解密

2023-03-07,,

当前使用的是Linux系统,已经按装使用OpenSSL软件包,

一、使用OpenSSL来生成私钥和公钥

1、执行命令openssl version -a 验证机器上已经安装openssl

1

openssl version -a

运行结果:

2、生成私钥:这条命令让openssl随机生成了一份私钥,加密长度是1024位。加密长度是指理论上最大允许”被加密的信息“长度的限制,也就是明文的长度限制。随着这个参数的增大(比方说2048),允许的明文长度也会增加,但同时也会造成计算复杂度的极速增长。一般推荐的长度就是2048位

1

openssl genrsa -out rsa_private_key.pem 2048

运行结果:

生产私钥文件:rsa_private_key.pem,内容都是标准的ASCII字符,开头一行和结尾一行有明显的标记,真正的私钥数据是中间的不规则字符

  

3、根据私钥生产公钥:rsa_public_key.pem

1

openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

运行结果:

公钥内容:

注意:此时的私钥还不能直接被使用,需要进行PKCS#8编码:

4、PKCS#8编码:指明输入私钥文件为rsa_private_key.pem,输出私钥文件为pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)

1

openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt

至此:可用的密钥对已经生成好了,私钥使用pkcs8_rsa_private_key.pem,公钥采用rsa_public_key.pem

至此,可用的密钥对已经生成好了,私钥使用pkcs8_rsa_private_key.pem,公钥采用rsa_public_key.pem。

最近又遇到RSA加密的需求了,而且对方要求只能使用第一步生成的未经过PKCS#8编码的私钥文件。后来查看相关文献得知第一步生成的私钥文件编码是PKCS#1格式,这种格式Java其实是支持的,只不过多写两行代码而已:

RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(priKeyData));
RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());
KeyFactory keyFactory= KeyFactory.getInstance("RSA");
PrivateKey priKey= keyFactory.generatePrivate(rsaPrivKeySpec);

首先将PKCS#1的私钥文件读取出来(注意去掉减号开头的注释内容),然后使用Base64解码读出的字符串,便得到priKeyData,也就是第一行代码中的参数。最后一行得到了私钥。接下来的用法就没什么区别了。

二、编写Java代码实际测试

RSA加密解密类:

  1 import java.io.BufferedReader;
2 import java.io.BufferedWriter;
3 import java.io.FileReader;
4 import java.io.FileWriter;
5 import java.io.IOException;
6 import java.security.InvalidKeyException;
7 import java.security.KeyFactory;
8 import java.security.KeyPair;
9 import java.security.KeyPairGenerator;
10 import java.security.NoSuchAlgorithmException;
11 import java.security.SecureRandom;
12
13 import java.security.interfaces.RSAPrivateKey;
14 import java.security.interfaces.RSAPublicKey;
15 import java.security.spec.InvalidKeySpecException;
16 import java.security.spec.PKCS8EncodedKeySpec;
17 import java.security.spec.X509EncodedKeySpec;
18
19 import javax.crypto.BadPaddingException;
20 import javax.crypto.Cipher;
21 import javax.crypto.IllegalBlockSizeException;
22 import javax.crypto.NoSuchPaddingException;
23
24 import org.apache.commons.codec.binary.Base64;
25
26 public class RSAEncrypt {
27 /**
28 * 字节数据转字符串专用集合
29 */
30 private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',
31 '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
32
33 /**
34 * 随机生成密钥对
35 */
36 public static void genKeyPair(String filePath) {
37 // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
38 KeyPairGenerator keyPairGen = null;
39 try {
40 keyPairGen = KeyPairGenerator.getInstance("RSA");
41 } catch (NoSuchAlgorithmException e) {
42 e.printStackTrace();
43 }
44 // 初始化密钥对生成器,密钥大小为96-1024位
45 keyPairGen.initialize(1024,new SecureRandom());
46 // 生成一个密钥对,保存在keyPair中
47 KeyPair keyPair = keyPairGen.generateKeyPair();
48 // 得到私钥
49 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
50 // 得到公钥
51 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
52 try {
53 // 得到公钥字符串
54 Base64 base64 = new Base64();
55 String publicKeyString = new String(base64.encode(publicKey.getEncoded()));
56 // 得到私钥字符串
57 String privateKeyString = new String(base64.encode(privateKey.getEncoded()));
58 // 将密钥对写入到文件
59 FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore");
60 FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore");
61 BufferedWriter pubbw = new BufferedWriter(pubfw);
62 BufferedWriter pribw = new BufferedWriter(prifw);
63 pubbw.write(publicKeyString);
64 pribw.write(privateKeyString);
65 pubbw.flush();
66 pubbw.close();
67 pubfw.close();
68 pribw.flush();
69 pribw.close();
70 prifw.close();
71 } catch (Exception e) {
72 e.printStackTrace();
73 }
74 }
75
76 /**
77 * 从文件中输入流中加载公钥
78 *
79 * @param in
80 * 公钥输入流
81 * @throws Exception
82 * 加载公钥时产生的异常
83 */
84 public static String loadPublicKeyByFile(String path) throws Exception {
85 try {
86 BufferedReader br = new BufferedReader(new FileReader(path
87 + "/publicKey.keystore"));
88 String readLine = null;
89 StringBuilder sb = new StringBuilder();
90 while ((readLine = br.readLine()) != null) {
91 sb.append(readLine);
92 }
93 br.close();
94 return sb.toString();
95 } catch (IOException e) {
96 throw new Exception("公钥数据流读取错误");
97 } catch (NullPointerException e) {
98 throw new Exception("公钥输入流为空");
99 }
100 }
101
102 /**
103 * 从字符串中加载公钥
104 *
105 * @param publicKeyStr
106 * 公钥数据字符串
107 * @throws Exception
108 * 加载公钥时产生的异常
109 */
110 public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
111 throws Exception {
112 try {
113 Base64 base64 = new Base64();
114 byte[] buffer = base64.decode(publicKeyStr);
115 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
116 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
117 return (RSAPublicKey) keyFactory.generatePublic(keySpec);
118 } catch (NoSuchAlgorithmException e) {
119 throw new Exception("无此算法");
120 } catch (InvalidKeySpecException e) {
121 throw new Exception("公钥非法");
122 } catch (NullPointerException e) {
123 throw new Exception("公钥数据为空");
124 }
125 }
126
127 /**
128 * 从文件中加载私钥
129 *
130 * @param keyFileName
131 * 私钥文件名
132 * @return 是否成功
133 * @throws Exception
134 */
135 public static String loadPrivateKeyByFile(String path) throws Exception {
136 try {
137 BufferedReader br = new BufferedReader(new FileReader(path
138 + "/privateKey.keystore"));
139 String readLine = null;
140 StringBuilder sb = new StringBuilder();
141 while ((readLine = br.readLine()) != null) {
142 sb.append(readLine);
143 }
144 br.close();
145 return sb.toString();
146 } catch (IOException e) {
147 throw new Exception("私钥数据读取错误");
148 } catch (NullPointerException e) {
149 throw new Exception("私钥输入流为空");
150 }
151 }
152
153 public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)
154 throws Exception {
155 try {
156 Base64 base64 = new Base64();
157 byte[] buffer = base64.decode(privateKeyStr);
158 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
159 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
160 return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
161 } catch (NoSuchAlgorithmException e) {
162 throw new Exception("无此算法");
163 } catch (InvalidKeySpecException e) {
164 throw new Exception("私钥非法");
165 } catch (NullPointerException e) {
166 throw new Exception("私钥数据为空");
167 }
168 }
169
170 /**
171 * 公钥加密过程
172 *
173 * @param publicKey
174 * 公钥
175 * @param plainTextData
176 * 明文数据
177 * @return
178 * @throws Exception
179 * 加密过程中的异常信息
180 */
181 public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
182 throws Exception {
183 if (publicKey == null) {
184 throw new Exception("加密公钥为空, 请设置");
185 }
186 Cipher cipher = null;
187 try {
188 // 使用默认RSA
189 cipher = Cipher.getInstance("RSA");
190 // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
191 cipher.init(Cipher.ENCRYPT_MODE, publicKey);
192 byte[] output = cipher.doFinal(plainTextData);
193 return output;
194 } catch (NoSuchAlgorithmException e) {
195 throw new Exception("无此加密算法");
196 } catch (NoSuchPaddingException e) {
197 e.printStackTrace();
198 return null;
199 } catch (InvalidKeyException e) {
200 throw new Exception("加密公钥非法,请检查");
201 } catch (IllegalBlockSizeException e) {
202 throw new Exception("明文长度非法");
203 } catch (BadPaddingException e) {
204 throw new Exception("明文数据已损坏");
205 }
206 }
207
208 /**
209 * 私钥加密过程
210 *
211 * @param privateKey
212 * 私钥
213 * @param plainTextData
214 * 明文数据
215 * @return
216 * @throws Exception
217 * 加密过程中的异常信息
218 */
219 public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)
220 throws Exception {
221 if (privateKey == null) {
222 throw new Exception("加密私钥为空, 请设置");
223 }
224 Cipher cipher = null;
225 try {
226 // 使用默认RSA
227 cipher = Cipher.getInstance("RSA");
228 cipher.init(Cipher.ENCRYPT_MODE, privateKey);
229 byte[] output = cipher.doFinal(plainTextData);
230 return output;
231 } catch (NoSuchAlgorithmException e) {
232 throw new Exception("无此加密算法");
233 } catch (NoSuchPaddingException e) {
234 e.printStackTrace();
235 return null;
236 } catch (InvalidKeyException e) {
237 throw new Exception("加密私钥非法,请检查");
238 } catch (IllegalBlockSizeException e) {
239 throw new Exception("明文长度非法");
240 } catch (BadPaddingException e) {
241 throw new Exception("明文数据已损坏");
242 }
243 }
244
245 /**
246 * 私钥解密过程
247 *
248 * @param privateKey
249 * 私钥
250 * @param cipherData
251 * 密文数据
252 * @return 明文
253 * @throws Exception
254 * 解密过程中的异常信息
255 */
256 public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)
257 throws Exception {
258 if (privateKey == null) {
259 throw new Exception("解密私钥为空, 请设置");
260 }
261 Cipher cipher = null;
262 try {
263 // 使用默认RSA
264 cipher = Cipher.getInstance("RSA");
265 // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
266 cipher.init(Cipher.DECRYPT_MODE, privateKey);
267 byte[] output = cipher.doFinal(cipherData);
268 return output;
269 } catch (NoSuchAlgorithmException e) {
270 throw new Exception("无此解密算法");
271 } catch (NoSuchPaddingException e) {
272 e.printStackTrace();
273 return null;
274 } catch (InvalidKeyException e) {
275 throw new Exception("解密私钥非法,请检查");
276 } catch (IllegalBlockSizeException e) {
277 throw new Exception("密文长度非法");
278 } catch (BadPaddingException e) {
279 throw new Exception("密文数据已损坏");
280 }
281 }
282
283 /**
284 * 公钥解密过程
285 *
286 * @param publicKey
287 * 公钥
288 * @param cipherData
289 * 密文数据
290 * @return 明文
291 * @throws Exception
292 * 解密过程中的异常信息
293 */
294 public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)
295 throws Exception {
296 if (publicKey == null) {
297 throw new Exception("解密公钥为空, 请设置");
298 }
299 Cipher cipher = null;
300 try {
301 // 使用默认RSA
302 cipher = Cipher.getInstance("RSA");
303 // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
304 cipher.init(Cipher.DECRYPT_MODE, publicKey);
305 byte[] output = cipher.doFinal(cipherData);
306 return output;
307 } catch (NoSuchAlgorithmException e) {
308 throw new Exception("无此解密算法");
309 } catch (NoSuchPaddingException e) {
310 e.printStackTrace();
311 return null;
312 } catch (InvalidKeyException e) {
313 throw new Exception("解密公钥非法,请检查");
314 } catch (IllegalBlockSizeException e) {
315 throw new Exception("密文长度非法");
316 } catch (BadPaddingException e) {
317 throw new Exception("密文数据已损坏");
318 }
319 }
320
321 /**
322 * 字节数据转十六进制字符串
323 *
324 * @param data
325 * 输入数据
326 * @return 十六进制内容
327 */
328 public static String byteArrayToString(byte[] data) {
329 StringBuilder stringBuilder = new StringBuilder();
330 for (int i = 0; i < data.length; i++) {
331 // 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
332 stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
333 // 取出字节的低四位 作为索引得到相应的十六进制标识符
334 stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
335 if (i < data.length - 1) {
336 stringBuilder.append(' ');
337 }
338 }
339 return stringBuilder.toString();
340 }
341 }

签名及校验类:

  1 import java.security.KeyFactory;
2 import java.security.PrivateKey;
3 import java.security.PublicKey;
4 import java.security.spec.PKCS8EncodedKeySpec;
5 import java.security.spec.X509EncodedKeySpec;
6
7 import org.apache.commons.codec.binary.Base64;
8
9 /**
10 * RSA签名验签类
11 */
12 public class RSASignature {
13
14 /**
15 * 签名算法
16 */
17 public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
18
19 /**
20 * RSA签名
21 *
22 * @param content
23 * 待签名数据
24 * @param privateKey
25 * 商户私钥
26 * @param encode
27 * 字符集编码
28 * @return 签名值
29 */
30 public static String sign(String content, String privateKey, String encode) {
31 try {
32 Base64 base64 = new Base64();
33 PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(base64.decode(privateKey));
34
35 KeyFactory keyf = KeyFactory.getInstance("RSA");
36 PrivateKey priKey = keyf.generatePrivate(priPKCS8);
37
38 java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
39
40 signature.initSign(priKey);
41 signature.update(content.getBytes(encode));
42
43 byte[] signed = signature.sign();
44
45 return new String(base64.encode(signed));
46 } catch (Exception e) {
47 e.printStackTrace();
48 }
49
50 return null;
51 }
52
53 public static String sign(String content, String privateKey) {
54 try {
55 Base64 base64 = new Base64();
56 PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(base64.decode(privateKey));
57 KeyFactory keyf = KeyFactory.getInstance("RSA");
58 PrivateKey priKey = keyf.generatePrivate(priPKCS8);
59 java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
60 signature.initSign(priKey);
61 signature.update(content.getBytes());
62 byte[] signed = signature.sign();
63 return new String(base64.encode(signed));
64 } catch (Exception e) {
65 e.printStackTrace();
66 }
67 return null;
68 }
69
70 /**
71 * RSA验签名检查
72 *
73 * @param content
74 * 待签名数据
75 * @param sign
76 * 签名值
77 * @param publicKey
78 * 分配给开发商公钥
79 * @param encode
80 * 字符集编码
81 * @return 布尔值
82 */
83 public static boolean doCheck(String content, String sign, String publicKey, String encode) {
84 try {
85 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
86 Base64 base64 = new Base64();
87 byte[] encodedKey = base64.decode(publicKey);
88 PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
89
90 java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
91
92 signature.initVerify(pubKey);
93 signature.update(content.getBytes(encode));
94
95 boolean bverify = signature.verify(base64.decode(sign));
96 return bverify;
97
98 } catch (Exception e) {
99 e.printStackTrace();
100 }
101
102 return false;
103 }
104
105 public static boolean doCheck(String content, String sign, String publicKey) {
106 try {
107 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
108 Base64 base64 = new Base64();
109 byte[] encodedKey = base64.decode(publicKey);
110 PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
111
112 java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
113
114 signature.initVerify(pubKey);
115 signature.update(content.getBytes());
116
117 boolean bverify = signature.verify(base64.decode(sign));
118 return bverify;
119
120 } catch (Exception e) {
121 e.printStackTrace();
122 }
123
124 return false;
125 }
126
127 }

最后是一个MainTest:

 1 import org.apache.commons.codec.binary.Base64;
2
3 public class MainTest {
4
5 public static void main(String[] args) throws Exception {
6 String filepath = "G:/tmp/";
7
8 // RSAEncrypt.genKeyPair(filepath);
9
10 Base64 base64 = new Base64();
11
12 System.out.println("--------------公钥加密私钥解密过程-------------------");
13 String plainText = "ihep_公钥加密私钥解密";
14 // 公钥加密过程
15 byte[] cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)),
16 plainText.getBytes());
17 String cipher = new String(base64.encode(cipherData));
18 // 私钥解密过程
19 byte[] res = RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)),
20 base64.decode(cipher));
21 String restr = new String(res);
22 System.out.println("原文:" + plainText);
23 System.out.println("加密:" + cipher);
24 System.out.println("解密:" + restr);
25 System.out.println();
26
27 System.out.println("--------------私钥加密公钥解密过程-------------------");
28 plainText = "ihep_私钥加密公钥解密";
29 // 私钥加密过程
30 cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)),
31 plainText.getBytes());
32 cipher = new String(base64.encode(cipherData));
33 // 公钥解密过程
34 res = RSAEncrypt.decrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)),
35 base64.decode(cipher));
36 restr = new String(res);
37 System.out.println("原文:" + plainText);
38 System.out.println("加密:" + cipher);
39 System.out.println("解密:" + restr);
40 System.out.println();
41
42 System.out.println("---------------私钥签名过程------------------");
43 String content = "ihep_这是用于签名的原始数据";
44 String signstr = RSASignature.sign(content, RSAEncrypt.loadPrivateKeyByFile(filepath));
45 System.out.println("签名原串:" + content);
46 System.out.println("签名串:" + signstr);
47 System.out.println();
48
49 System.out.println("---------------公钥校验签名------------------");
50 System.out.println("签名原串:" + content);
51 System.out.println("签名串:" + signstr);
52
53 System.out.println("验签结果:" + RSASignature.doCheck(content, signstr, RSAEncrypt.loadPublicKeyByFile(filepath)));
54 System.out.println();
55
56 }
57 }

参考:

http://blog.csdn.net/chaijunkun/article/details/7275632

http://blog.csdn.net/wangqiuyun/article/details/42143957

Java中使用OpenSSL生成的RSA公私钥进行数据加解密的相关教程结束。

《Java中使用OpenSSL生成的RSA公私钥进行数据加解密.doc》

下载本文的Word格式文档,以方便收藏与打印。