咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

RSA加密解密实践

AES是非对称加密,有公钥/私钥。

一、创建秘钥对

openssl和jdk都可以生成秘钥对,但要注意的是他们会有默认规范,这可能会导致在不同的平台上不通用。推荐在线生成。

1. 在线生成

【在线生成公钥私钥对,RSA公私钥生成】 可以在线生成。

RSA非对称加密公私钥对生成,输出PEM格式的公私钥对,同时支持PKCS#1、PKCS#8密钥格式输出;生成的公私钥对,可拷贝到文本文件,保存为.key文件即可使用。

PEM格式:RSA公私钥对常用的编码方式,OPENSSL以PEM格式为主,相对DER可读性更强,以BASE64编码呈现;
开头类似 —–BEGIN PRIVATE KEY—–
结尾类似 —–END PRIVATE KEY—–

PKCS#8密钥格式,多用于JAVA、PHP程序加解密中,为目前用的比较多的密钥、证书格式;
PKCS#1密钥格式,多用于JS等其它程序加解密,属于比较老的格式标准。
PKCS#1和PKCS#8的主要区别,从本质上说,PKCS#8格式增加验证数据段,保证密钥正确性。

2. openssl生成

生成私钥,长度1024(一般会推荐2048)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ openssl version
OpenSSL 1.1.1f 31 Mar 2020
$ openssl genrsa -out rsa_private_key.pem 1024
Generating RSA private key, 1024 bit long modulus (2 primes)
...............+++++
...................................................+++++
e is 65537 (0x010001)
$ cat rsa_private_key.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDMtvNrm4VDreYXzMRnJ4htiBPnnw9djDL5aLQUYm3w2TQ0CGD1
KMBhsm7hC5sf4RkODQYq6Wp1mkL30GStfbaal1S9ILnt9w51P0IpOqAFNZ6jwAtr
WUhUhrr+33vcJ8gQh4+fJcAEXvrWbNnTCj9zHFDMelo7bR2PsDLJ6jqqkwIDAQAB
AoGBAKFO9AZx2JOY3rsYPhaufwEX/d9AZcIn7C69Q1DgspLbBBiQFZ54iwcwq9Am
7ggzviNlPdvoa1vZvzU4f2x5p71FIGZn6rSb00TB4GxvXox1VOd9bcdj0iDrclDu
O/Wt408Pct1TpYA2OwoxFvSgY5wxpZilxHiiRghypFK5sooZAkEA9Zh3Vfq12+fR
8EDHHZKKtJug+jnuSdnoZIjhjB8Ki7Uor/+uQlxjoTW/PwYJKCoIFBhIcBA1h5tl
zCQHPgCcBQJBANVjH3IYUGtC834DvIaZQCCa9oG38cbnSF5mqPrhV769hXXsc0XM
I2/ZitKCFC0vg/D3lCE52vPi4w142tMbB7cCQQC/nCuG1iqqnivp8PAof1teW4l1
kFr8HVm1jiHCi7lTlIxg++898Qz+CoviJNhiEKDq5KMnY04QNcpvQbCwzBLtAkEA
kcAuzmPFKj6EymIK93Td1GeEUH4v6sg3KiO87//TSzlwW2eyJM6WteNFaxvmZCa8
XG7/AuLdpxAmPiF6dg9UaQJAVP+oZrFdqBvutIBlLdg9ZmLXHwk4oqbLexcPI4mB
+bc0Qeuv4vV1x6M/024Ae6SCC4ywnx9xNVTedn6siZfNNQ==
-----END RSA PRIVATE KEY-----

根据私钥生成公钥

1
2
3
4
5
6
7
8
9
10
$ openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
writing RSA key

$ cat rsa_public_key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMtvNrm4VDreYXzMRnJ4htiBPn
nw9djDL5aLQUYm3w2TQ0CGD1KMBhsm7hC5sf4RkODQYq6Wp1mkL30GStfbaal1S9
ILnt9w51P0IpOqAFNZ6jwAtrWUhUhrr+33vcJ8gQh4+fJcAEXvrWbNnTCj9zHFDM
elo7bR2PsDLJ6jqqkwIDAQAB
-----END PUBLIC KEY-----

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt

$ cat pkcs8_rsa_private_key.pem
-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMy282ubhUOt5hfM
xGcniG2IE+efD12MMvlotBRibfDZNDQIYPUowGGybuELmx/hGQ4NBirpanWaQvfQ
ZK19tpqXVL0gue33DnU/Qik6oAU1nqPAC2tZSFSGuv7fe9wnyBCHj58lwARe+tZs
2dMKP3McUMx6WjttHY+wMsnqOqqTAgMBAAECgYEAoU70BnHYk5jeuxg+Fq5/ARf9
30BlwifsLr1DUOCyktsEGJAVnniLBzCr0CbuCDO+I2U92+hrW9m/NTh/bHmnvUUg
ZmfqtJvTRMHgbG9ejHVU531tx2PSIOtyUO479a3jTw9y3VOlgDY7CjEW9KBjnDGl
mKXEeKJGCHKkUrmyihkCQQD1mHdV+rXb59HwQMcdkoq0m6D6Oe5J2ehkiOGMHwqL
tSiv/65CXGOhNb8/BgkoKggUGEhwEDWHm2XMJAc+AJwFAkEA1WMfchhQa0LzfgO8
hplAIJr2gbfxxudIXmao+uFXvr2FdexzRcwjb9mK0oIULS+D8PeUITna8+LjDXja
0xsHtwJBAL+cK4bWKqqeK+nw8Ch/W15biXWQWvwdWbWOIcKLuVOUjGD77z3xDP4K
i+Ik2GIQoOrkoydjThA1ym9BsLDMEu0CQQCRwC7OY8UqPoTKYgr3dN3UZ4RQfi/q
yDcqI7zv/9NLOXBbZ7Ikzpa140VrG+ZkJrxcbv8C4t2nECY+IXp2D1RpAkBU/6hm
sV2oG+60gGUt2D1mYtcfCTiipst7Fw8jiYH5tzRB66/i9XXHoz/TbgB7pIILjLCf
H3E1VN52fqyJl801
-----END PRIVATE KEY-----

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

3. Java代码生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
//X509规范
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//PKCS#8规范
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

System.out.println("-----BEGIN PUBLIC KEY-----");
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("-----END PUBLIC KEY-----");

System.out.println("\n");

System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
System.out.println("-----END PRIVATE KEY-----");

二、加密解密

这里采用的是上面的 “【openssl生成】” 的秘钥对。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class TestRsa4 {
private static final String PRI_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMy282ubhUOt5hfMxGcniG2IE+efD12MMvlotBRibfDZNDQIYPUowGGybuELmx/hGQ4NBirpanWaQvfQZK19tpqXVL0gue33DnU/Qik6oAU1nqPAC2tZSFSGuv7fe9wnyBCHj58lwARe+tZs2dMKP3McUMx6WjttHY+wMsnqOqqTAgMBAAECgYEAoU70BnHYk5jeuxg+Fq5/ARf930BlwifsLr1DUOCyktsEGJAVnniLBzCr0CbuCDO+I2U92+hrW9m/NTh/bHmnvUUgZmfqtJvTRMHgbG9ejHVU531tx2PSIOtyUO479a3jTw9y3VOlgDY7CjEW9KBjnDGlmKXEeKJGCHKkUrmyihkCQQD1mHdV+rXb59HwQMcdkoq0m6D6Oe5J2ehkiOGMHwqLtSiv/65CXGOhNb8/BgkoKggUGEhwEDWHm2XMJAc+AJwFAkEA1WMfchhQa0LzfgO8hplAIJr2gbfxxudIXmao+uFXvr2FdexzRcwjb9mK0oIULS+D8PeUITna8+LjDXja0xsHtwJBAL+cK4bWKqqeK+nw8Ch/W15biXWQWvwdWbWOIcKLuVOUjGD77z3xDP4Ki+Ik2GIQoOrkoydjThA1ym9BsLDMEu0CQQCRwC7OY8UqPoTKYgr3dN3UZ4RQfi/qyDcqI7zv/9NLOXBbZ7Ikzpa140VrG+ZkJrxcbv8C4t2nECY+IXp2D1RpAkBU/6hmsV2oG+60gGUt2D1mYtcfCTiipst7Fw8jiYH5tzRB66/i9XXHoz/TbgB7pIILjLCfH3E1VN52fqyJl801";
private static final String PUB_KEY ="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMtvNrm4VDreYXzMRnJ4htiBPnnw9djDL5aLQUYm3w2TQ0CGD1KMBhsm7hC5sf4RkODQYq6Wp1mkL30GStfbaal1S9ILnt9w51P0IpOqAFNZ6jwAtrWUhUhrr+33vcJ8gQh4+fJcAEXvrWbNnTCj9zHFDMelo7bR2PsDLJ6jqqkwIDAQAB";

public static void main (String[] args) throws Exception {

String encr = encrypted("1212121212", PUB_KEY);
String result = decrypt(encr, PRI_KEY);
System.out.println(result);
}

public static String encrypted (String content,String pubkey) throws Exception {

//先还原公钥的密钥,再加密
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubkey));
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)));
}

public static String decrypt (String cryptograph, String prikey) throws Exception {

//先还原私钥的密钥,再解密
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(prikey));
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);

byte[] b = Base64.getDecoder().decode(cryptograph);
return new String(cipher.doFinal(b));
}
}