RSA
非对称加密,公钥加密,私钥解密,反之亦然。由于需要大数的乘幂求模等算法,运行速度慢,不易于硬件实现。
通常私钥长度有512bit,1024bit,2048bit,4096bit,长度越长,越安全,但是生成密钥越慢,加解密也越耗时。
既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;
同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。
AES
对称加密,密钥最长只有256个bit,执行速度快,易于硬件实现。由于是对称加密,密钥需要在传输前通讯双方获知。
基于以上特点,通常使用RSA来首先传输AES的密钥给对方,然后再使用AES来进行加密通讯。
以上内容参考:
我们在项目中是采用:
首先随机生成单次请求加密密钥(clientAesKey,长度为 16 位,可以用 26 个字母和数字组成)
RSA负责加密一个字符串(clientAesKey)、
AES负责用这个字符串(clientAesKey)、明文加密为一个密文。
解密时首先要用RSA获取这个字符串(clientAesKey)、然后再用AES解密密文。
项目加密解密完整步骤为:
1.1.1. 步骤说明
clientAesKey:客户端随机生成 AESKey,用于 AES 加密(长度为 16 位,可以用 26 个字母和数字组成)。
serverAesKey:服务端随机生成 AESKey,用于 AES 加密(长度为 16 位,可以用 26 个字母和数字组成)。
clientPrivateKey:客户端私钥,用 RSA 算法生成。
clientPublickey:客户端公钥,用 RSA 算法生成。
serverPrivateKey:服务端私钥,用 RSA 算法生成。
serverPublickey:服务端公钥,用 RSA 算法生成。
Step1:生成基本业务参数,例如参数值为:
{" source": "2"," name": "黄磊"}
Step2:业务请求参数按参数名排序(按照字母顺序排序,从 a-z)
(实际我们这里没有排序,是按原来顺序直接取的参数值拼接为字符串。注意确认是否排序了。)
Step3:排序后的业务请求参数值拼接成字符串,例如参数值拼接成的字符串为:
paramValue="2黄磊"
Step4:根据 RAS 客户端私有密钥签名业务请求参数值字符串(paramValue),生成基于SHA1 的 RSA 数字签名sign =RSA.sign(paramValue, clientPrivateKey);
Step5:将签名合并到业务请求参数中,并生成 JSON 格式字符串,如下:
realdata={" source": "2"," name": "黄磊","sign":"ExdY cut6LgrKGsHuAyoxFTMDuDYVmyFFu7GRHPRwB/DBwm6cyBe9Sr2rti1/SjWPcdXLoWIH1/Bv7ck="}
Step6:随机生成单次请求加密密钥(clientAesKey,长度为 16 位,可以用 26 个字母和数字组成)
Step7:通过 clientAesKey加密业务请求的 JSON 格式字符串(realdata),生成通
信密文
Stringdata =AES.encryptToBase64(realdata, clientAesKey);
Step8:使用 RSA 加密 clientAesKey生成密钥密文
String encryptkey =RSA. encryptToBase64 (clientAesKey, serverPublickey);
Step9:向 API 接口发生 HTTP 请求,请求的参数包括data、encryptkey,appid。
Step10:接收接口处理结果(JSON 格式,包含 data 和 encryptkey,appid),如下
{"data":
"zxaauDc3oV5IRk41rj2u130RWd6Qf5WhLe5wwu0uRxmsnmwAZAWBk0zzriPEY3F29Ak=",
"encryptkey":
"D1FazeaObn5YVyAEkgLz2CZmQOb+7nsM0O1tliedDY7FAnWdv4Xmjm4P2Lnx3nNIpQ5D0aQ+r6hzg8=", “appid”:”cmzt”}
Step11:用 RSA 解密接口返回的密钥密文 encryptkey,获取 serverAesKey。
serverAesKey =RSA.decrypFromBase64(encryptkey, clientPrivateKey);
Step12:用 serverAesKey将接口返回的业务密文 data 解密
String serverRealData =AES.decryptFromBase64(data, serverAesKey);
Step13:将 serverRealData中除了 sign 之外的参数按键排序,并将参数值拼成字符串signData
Step14:用 RSA 验证签名是否正确
boolean result =RSA.checkSign(signData,sign, serverPublickey);
Step15:验证的签名通过后认可返回的 data 明文 serverRealData。
总结:一般来说只要我们保存好公钥、私钥,就不会有问题。如果私钥泄露那肯定会有问题的。
就像我们平时的手机验证码一样,如果你泄露了,那么就不安全了。
其实上面的加密、解密过程比较复杂,加密、解密效率也比较低,不适合有较大的数据量传输。都在一个密文可能就是上百万个字符。
但是目前还不知道怎么优化,只有后续了.........