RSA算法是公开密钥系统的代表,其安全性建立在具有大素数因子的合数,其因子分解困难这一法则之上的。Rijndael算法作为新一代的高级加密标准,运行时不需要计算机有非常高的处理能力和大的内 存,操作可以很容易的抵御时间和空间的攻击,在不同的运行环境下始终能保持良好的性能。这使AES将安全,高效,性能,方便,灵活性集于一体,理应成为网 络数据加密的首选。相比较,因为AES密钥的长度最长只有256比特,可以利用软件和硬件实现高速处理,而RSA算法需要进行大整数的乘幂和求模等多倍字 长处理,处理速度明显慢于AES[5];所以AES算法加解密处理效率明显高于RSA算法。在密钥管理方面,因为AES算法要求在通信前对密钥进行秘密分 配,解密的私钥必须通过网络传送至加密数据接收方,而RSA采用公钥加密,私钥解密(或私钥加密,公钥解密),加解密过程中不必网络传输保密的密钥;所以 RSA算法密钥管理要明显优于AES算法。
从上面比较得知,由于RSA加解密速度慢,不适合大量数据文件加密,因此在网络中完全用公开密码体制传 输机密信息是没有必要,也是不太现实的。AES加密速度很快,但是在网络传输过程中如何安全管理AES密钥是保证AES加密安全的重要环节。这样在传送机 密信息的双方,如果使用AES对称密码体制对传输数据加密,同时使用RSA不对称密码体制来传送AES的密钥,就可以综合发挥AES和RSA的优点同时避 免它们缺点来实现一种新的数据加密方案。加解密实现流程如下图。
具体过程是先由接收方创建RSA密钥对,接收方通过Internet发送RSA公钥到发送方,同时保存RSA私钥。而发送方创建AES密钥,并用该 AES密钥加密待传送的明文数据,同时用接受的RSA公钥加密AES密钥,最后把用RSA公钥加密后的AES密钥同密文一起通过Internet传输发送 到接收方。当接收方收到这个被加密的AES密钥和密文后,首先调用接收方保存的RSA私钥,并用该私钥解密加密的AES密钥,得到AES密钥。最后用该 AES密钥解密密文得到明文。
AES+RSA结合最佳实践
基本要求
- 保证传输数据的安全性
- 保证数据的完整性
- 能够验证客户端的身份
基本流程
- 服务器端(server)和客户端(client)分别生成自己的密钥对
- server和client分别交换自己的公钥
- client生成AES密钥(aesKey)
- client使用自己的RSA私钥(privateKey)对请求明文数据(params)进行数字签名
- 将签名加入到请求参数中,然后转换为json格式
- client使用aesKey对json数据进行加密得到密文(data)
- client使用sever的RSA公钥对aesKey进行加密(encryptkey)
- 分别将data和encryptkey作为参数传输给服务器端
服务器端进行请求响应时将上面流程反过来即可
原理性的东西就到这里了,接下来如何实战操作呢,当初弄这个跟后台调了好几天才调通,这里全部贴出来方便大家参考的同时也是给自己做个笔记!
生成证书
RSA加密是需要公钥和私钥的,第一个坑:Apple是不支持直接使用字符串进行加密解密的,推荐使用p12文件这里就把客户端和服务端所需要证书的生成步骤贴出来,打开终端cd到你保存证书的目录:
1.生成模长为1024bit的私钥openssl genrsa -out private_key.pem 1024
2.生成certification require fileopenssl req -new -key private_key.pem -out rsaCertReq.csr
注意:在这一步会要求你输入一些信息,不需要理会,直接按enter健就行了。
3.生成certification 并指定过期时间openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt
4.生成公钥供iOS使用openssl x509 -outform der -in rsaCert.crt -out public_key.der
5.生成私钥供iOS使用 这边会让你输入密码,后期用到在生成secKeyRef的时候会用到这个密码openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
6.生成pem结尾的公钥供Java使用openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
7.生成pem结尾的私钥供Java使用openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
这里一共生成了7个文件。要使用RSA+AES加密需要用2套证书,然后客户端和服务端交换公钥。这里只是其中一套,再重复上面7个步骤再生成一套,我们的证书就算弄完了。
AES加密
代码就不贴了,可以直接去看demo,这里说一下踩过的坑。当初在调试这个的时候服务端一直无法解密iOS传过来的密文,初步设想是AES加密的时候设置的一些参数不一样导致的,所以就和服务端一个一个的对。
- 密钥长度(Key Size)
- 加密模式(Cipher Mode)
- 填充方式(Padding)
- 初始向量(Initialization Vector)
以上这几个参数是必须要两端统一的。
密钥长度
AES算法下,key的长度有三种:128、192和256 bits。由于历史原因,JDK默认只支持不大于128 bits的密钥,而128 bits的key已能够满足商用安全需求。demo中是统一使用这个size_t const kKeySize = kCCKeySizeAES128;
加密模式
AES属于块加密(Block Cipher),块加密中有CBC、ECB、CTR、OFB、CFB等几种工作模式。demo中统一使用CBC即对应后面的填充模式kCCOptionPKCS7Padding
填充方式
java的填充方式是PKCS5Padding,而iOS的则只有PKCS7Padding,但是其实这两个是一样的,大家不要误解了。
初始向量
使用除ECB以外的其他加密模式均需要传入一个初始向量,其大小与Block Size相等(AES的Block Size为128 bits),而两个平台的API文档均指明当不传入初始向量时,系统将默认使用一个全0的初始向量。
此外还需注意utf-8编码和base64编码是否和服务端对得上。
AES与RSA相结合数据加密方案
RSA签名和加密
RSA签名:就是只有信息的发送者才能产生,别人无法伪造的一段数字串,是对发送者发送的信息的真实性的一个证明。
在签名时一般是先用哈希函数计算出被签名信息惟一的哈希结果值(为实用目的,降低加密成本,RSA加密不适用于大数据量加密).最后使用私钥将哈希结果值转化为数字签名。
|
|
注意:这些参数函数getHashBytes
就是得到签名信息的哈希结果值,kChosenDigestLength
这个签名长度参数和padding
值kSecPaddingPKCS1SHA1
均要与服务端保持一致
|
|
RSA加密核心代码
|
|
这里同样要注意的还是padding值kSecPaddingPKCS1必须要与服务端一致
|
|
综上AES+RSA加密方案的流程代码如下,具体的可以参考完整代码AES+RSA加密Demo。
|
|