RSA取名来自Ron Rivest、Adi Shamirh和LenAdleman三个发明者的名字。

RSA原理:RSA算法基于一个十分简单的数论事实,将两个大素数相乘十分容易,但反过来想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

RSA缺点:RSA的keysize位数越高,其产生密钥对及加密、解密的速度越慢,这是基于大素数非对称加密算法的缺陷。

使用OpenSSL来生成私钥和公钥

查看版本信息:

ershixiongdeMacBook-Pro:~ zzs$ openssl version -a
OpenSSL 0.9.8zh 14 Jan 2016
built on: Nov 19 2017
platform: darwin64-x86_64-llvm
options:  bn(64,64) md2(int) rc4(ptr,char) des(idx,cisc,16,int) blowfish(idx)
compiler: -arch x86_64 -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O3 -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DMD32_REG_T=int -DOPENSSL_NO_IDEA -DOPENSSL_PIC -DOPENSSL_THREADS -DZLIB -mmacosx-version-min=10.6
OPENSSLDIR: "/System/Library/OpenSSL"

生成私钥:

ershixiongdeMacBook-Pro:~ zzs$ openssl genrsa -out rsa_private_key.pem 1024
Generating RSA private key, 1024 bit long modulus
..++++++
................++++++
e is 65537 (0x10001)

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

ershixiongdeMacBook-Pro:~ zzs$ cat rsa_private_key.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDQtmuOBLnIcRxy+R7cLMrttBGcNlfTouw4t/dZId5xYd/F76E3
wk3dk0QIYEUVY1bZY8sq7Xv8AzzcnsRi5DM3jxHRl8vGu50TjKLhEG5y+z//LrOe
XyLaKRMPBp1bP9vk4gJrXJGrQpX4aNZEsTor/07tG+onRQXup/RLHS0lkQIDAQAB
AoGBAILcTbV+6wltOjwwTJQaFaZSh9QdEpYkid3KIvEk1jba+hY9+CRg1Ld/tWFX
Exmk7nhhJKqmul05nnhpp5KlqCIjxY5jt1CbX2CxEGN0fJKyzVxKV8Tik9iI246x
vVh6VhbBDhommpjS0TxZNgNowMzXqIhii4sgwmvn0TZ9CCCrCQ2687ey2CyUCGGF
mEpUtrAnMwJBANQFdjrXwxbRmlLU+T3I1P/U2r4B/eW6OdKSGpTQEsbH3uL0rmxn
6funBtaxCzaawkGfUw4FOXEiwBkhcdZWJKj/hvqLTXocw2PLiEKOxqjWjebjAkEA
kqVIdkCf9ht5gws9bQeIk36U4VEdXJSmw8c8TWtxYT4DIrUcI2y2eKDEJ9RYNrop
Wrdh9+yvt7Rr7RswTUQ8ywJBANJ+RdtARPS+nHhddw47lLo000UT38AkCcoa4q9k
F0+mizZUwhJzdOk4qCOM0jSVF0uV/ois4FkE+cfXTdaonyg=
-----END RSA PRIVATE KEY-----

内容都是标准的ASCII字符,开头一行和结尾一行有明显的标记,真正的私钥数据是中间的不规则字符。

密钥文件最终将数据通过Base64编码进行存储。可以看到上述密钥文件内容每一行的长度都很规律。这是由于RFC2045中规定:The encoded output stream must be represented in lines of no more than 76 characters each。也就是说Base64编码的数据每行最多不超过76字符,对于超长数据需要按行分割。

根据私钥生成公钥:

ershixiongdeMacBook-Pro:~ zzs$ openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
writing RSA key

查看公钥内容:

ershixiongdeMacBook-Pro:~ zzs$ cat rsa_public_key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQtmuOBLnIcRtBGc
NlfTouw4t/dZId5xYd/F76E3wk3dk0QIYEUVY1bZY8sq7Xv8AzzcjxHR
l8vGu50TjKLhEG5y+rOeXyLaKRMPBp1bP9vk4gJrXJGrQpX4aNZEsTor/07t
G+onRQXup/RLHS0lkQIDAQAB
-----END PUBLIC KEY-----

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

ershixiongdeMacBook-Pro:~ zzs$ openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt

命令中指明了输入私钥文件为rsa_private_key.pem,输出私钥文件为pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)
再来看一下,编码后的私钥文件是不是和之前的私钥文件不同了:

ershixiongdeMacBook-Pro:~ zzs$ cat pkcs8_rsa_private_key.pem
-----BEGIN PRIVATE KEY-----
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBANC2a44EuchxHHL5
Htwsyu20EZw2V9Oi7Di391kh3nFh38XvoTfCTd2TRAhgRRVjVtljyyrte/wDPNye
xGLkMzePEdGXy8a7nROMouEQbnL7P/8us55fItopEw8GnVs/2+TiAmtckatClfho
1B0SliSJ3coi8STWNtr6Fj34JGDUt3+1YVcTGaTueGEkqqa6XTmeeGmnkqWoIiPF
G4Wl9VIhfxnh/DA0BJ0CQQD8AUKXMzKYdAC9WHpWFsEOGiaamNLRPFk2A2jAzNeo
iGKLiyDCa+fRNn0IIKsJDbrzt7LYLJQIYYWYSlS2sCczAkEA1AV2OtfDFtGaUtT5
fM8wKwJBAMKC0nxURzRHLZ74oQy76W1SIAPp+6cG1rELNprCQZ9TDgU5cSLAGSFx
1lYkqP+G+otNehzDY8uIQo7GqNaN5uMCQQCSpUh2QJ/2G3mDCz1tB4iTfpThUR1c
20BE9L6ceF13DjuUujTTRRPfwCQJyhrir2QXT6aLNlTCEnN06TioI4zSNJUXS5X+
iKzgWQT5x9dN1qifKA==
-----END PRIVATE KEY-----

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

第一步生成的私钥文件编码是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,也就是第一行代码中的参数。最后一行得到了私钥。接下来的用法就没什么区别了。
参考文献:https://community.oracle.com/thread/1529240?start=0&tstart=0

加载公钥与加载私钥的不同点在于公钥加载时使用的是X509EncodedKeySpec(X509编码的Key指令),私钥加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。



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

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:https://choupangxia.com/2020/08/21/java-openssl-rsa/