Java中使用OpenSSL生成的RSA公私钥进行数据加解密
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指令)。
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接