Java实现的RSA双向通讯加密组件

在公司主要负责的是对其他的系统提供接口访问,主要包含了付款等金融业务,之前的接口虽然也用了RSA私钥对报文进行签名,但是私钥直接写进了客户端的代码里,可以说是一点卵用都没有。
经过一番学习,实现了一套通讯双方互换公钥的方案,通信报文使用Aes256加密,SHA1摘要经过私钥加密后当做签名,具体代码放在了Github,有兴趣的可以研究一下,里面的异常和日志由于是移植了部分代码,没有进行处理,需要的可以自行处理。

生成公私钥

这里用的是JKS组件,需要有Java环境的机器来执行

密钥库文件及私钥

里面的参数需要自己进行调整

1
keytool -genkey -alias alias -keyalg RSA -keystore test.keystore -validity 1830 -keysize 2048 -storepass password -keypass password -dname "CN=test,OU=test,O=test,L=test,ST=test,C=test"

生成公钥证书文件

1
keytool -export -alias alias -keystore test.keystore -file test.cer

详细设计

由于RSA加密的性能比较差,所以一般采用的方案都是对完整报文进行对称加密,然后需要做的就是如何把正确的对称加密的密钥发送给对方,这里采用的方案是将加密使用的AESkey使用对方的公钥进行加密,key的长度比较短所以对性能的影响不算很大。
这里设定本身是A,手里有自己的私钥A.privateKey和对方B的证书,即公钥B.publicKey
同样对方B,手里有他自己的私钥B.privateKey和我们自己的证书,即公钥A.publicKey

加密/签名


这里我们采用了常用的AES-256的加密,在现阶段可以时说是安全的高级加密标准-wiki
生成一个随机的AES256位密钥,对报文加密得到了encryptedData,然后使用SHA-1计算encryptedData的摘要值,然后使用自己的私钥A.privateKey对摘要值进行签名得到了sign,对方可以使用签名来验证报文的确是你发送的,验证方法后续会叙述。
最后,我们肯定不能明文传送加解密时使用的秘钥AESKey,所以我们使用对方的公钥B.publicKey对秘钥进行加密得到了encrypedAESKey
至此,我们得到了所有要发送给对方的内容:encryptedDatasignencrypedAESKey

验签/解密


由于对接难度的问题,我没有对报文的时间,以及公私钥的时间进行验证,如果需要的话可以添加,公私钥的时间验证代码里也有包含,但是没有使用
当对方收到了我们发来的加密信息以后,首先要对签名进行验证
encryptedData进行相同的操作,使用SHA-1计算出加密数据的摘要值SHA-1,然后使用A的公钥A.publicKey对签名sign进行验签(解密)得到verify,然后对比SHA-1verify是否一致,如果两个数据不同的话,说明报文被中间人进行了修改。
如果验签成功,这时候就开始对报文进行解密,使用B.publicKey对加密的秘钥encryptedAESKey进行解密得到了明文的AES秘钥AESKey,然后使用秘钥对加密的报文encryptedData进行解密,即可得到完整的明文报文了。