iOS使用AES+RSA加密

由于项目中,登录请求过程中涉及到用户数据的传输,为了用户数据的安全性考虑,决定在请求与相应中使用加密传输的方式。查找了相关资料后发现,目前最广泛的是使用AES+RSA组合加密的方式。即采用对称加密与非对称加密相结合的方式,综合了对称加密的高效与非对称加密的安全性,是目前大多数项目采用的方式。其大致的思路如下:

  1. 首先使用AES对称加密加密要传输的数据(由于数据可能会比较大,所以如果使用RSA非对称加密的话,就很耗性能,影响用户体验)。
  2. 然后用非对称加密RSA来加密AES加密所使用的密钥key
  3. 最后把AES加密后的数据,与RSA加密后的key发给服务器,同理后台也使用此方法来进行数据传输。

下面就针对AES与RSA加密的方式以及项目中遇到的问题做下简单的说明。

首先先看下加密的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 使用AES128 加密
//随机生成16位字符串的AES 加密的密钥key
NSString *key = [SecurityUtil randomlyGenerated16BitString];
NSLog(@"AES加密的秘钥key=%@",key);
NSLog(@"disJson = %@",[kutils JsonSerializer:dicJson]);
NSString *encodeBase64 = aesEncryptString([kutils JsonSerializer:dicJson], key);
NSLog(@"AES128加密:%@",encodeBase64);
NSString *decryptedText = aesDecryptString(encodeBase64, key);
NSLog(@"AES解密后的%@", decryptedText);
/************************
RAS 加密 ASE的KEY
****************************/
//给随机KEY 加密
NSString *encWithPubKey = [SecurityUtil encryptString:key publicKey:RSApublicKey];
//RSApublicKey RSA加密的公钥
NSLog(@"RSA加密后的key:%@",encWithPubKey);
NSMutableDictionary *encryptJsonDict = [NSMutableDictionary dictionary];
[encryptJsonDict setValue:encWithPubKey forKey:@"key"];
[encryptJsonDict setValue:encodeBase64 forKey:@"value"];

dicJson = encryptJsonDict;

解密的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NSDictionary *temDic = [kutils JsonDeserializer:dataStr];//json解析
NSString *key = [temDic valueForKey:@"key"];
NSString *value = [temDic valueForKey:@"value"];
//RSA公钥解密服务端传过来的AES加密的key
if (key == nil) {
NSLog(@"发送登录请求后传过来的字典其中的key为nil");
}
NSString *AES_key = [SecurityUtil decryptString:key?:@"key" publicKey:RSApublicKey];
//然后使用key 来解密AES加密后的value
if (AES_key && value) {
NSString *dicString = aesDecryptString(value, AES_key);
NSLog(@"解密后的dicStrign = %@",dicString);
dic = [kutils JsonDeserializer:dicString];
} else {
NSLog(@"AES_key 或则value为nil AES_key = %@ value = %@",AES_key,value);
}

项目中遇到的问题:

  • AES加密后的数据服务端无法解析

原因分析:由于 当时我使用的AES加密,设置了填充方式初始向量,交流后发现我们呢后台使用JavaAES加密,他们说找不到设置这两项的方法(我这里觉得肯定是可以设置),没办法,只好没有设置初始向量以及填充方式设置为kCCOptionECBMode | kCCOptionPKCS7Padding

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
NSString const *kInitVector = @"";//@"A-16-Byte-String";
size_t const kKeySize = kCCKeySizeAES128;

NSData * cipherOperation(NSData *contentData, NSData *keyData, CCOperation operation) {
NSUInteger dataLength = contentData.length;

void const *initVectorBytes = [kInitVector dataUsingEncoding:NSUTF8StringEncoding].bytes;
void const *contentBytes = contentData.bytes;
void const *keyBytes = keyData.bytes;

size_t operationSize = dataLength + kCCBlockSizeAES128;
void *operationBytes = malloc(operationSize);
if (operationBytes == NULL) {
return nil;
}
size_t actualOutSize = 0;

CCCryptorStatus cryptStatus = CCCrypt(operation,
kCCAlgorithmAES,
kCCOptionECBMode | kCCOptionPKCS7Padding,
keyBytes,
kKeySize,
initVectorBytes,
contentBytes,
dataLength,
operationBytes,
operationSize,
&actualOutSize);

if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:operationBytes length:actualOutSize];
}
free(operationBytes);
operationBytes = NULL;
return nil;
}

关于AES加密参数的说明,这里有更加详细的说明大家可以参考:AES加密

  • 后台发送过来的AES加密后数据iOS端无法正确解析此问题很奇怪?

因为在demo测试时候,我的客户端是可以正确解析的,但是当在项目中测试的时候发现解析不了,(测试时用的数据很小)最后交流中发现问题所在,我iOS 上AES生成的随机密钥key是字符串格式的,而后台端Java直接是生成二进制格式的密钥key,两端格式没有统一,最后后代改为使用字符串格式的密钥key后,就可以正常解析了。

说明:RSA的公钥我这里采用的Java后台生成的经过base64后的字符串。

ASE+RSA代码下载

感谢您的阅读,本文由 蜂子fightting 原创提供。如若转载,请注明出处:蜂子fightting(https://www.jianshu.com/u/cfa683de4381
runtime 运行时--篇章二