由于项目中,登录请求过程中涉及到用户数据的传输,为了用户数据的安全性考虑,决定在请求与相应中使用加密传输的方式。查找了相关资料后发现,目前最广泛的是使用AES+RSA组合加密的方式。即采用对称加密与非对称加密相结合的方式,综合了对称加密的高效与非对称加密的安全性,是目前大多数项目采用的方式。其大致的思路如下:
- 首先使用AES对称加密加密要传输的数据(由于数据可能会比较大,所以如果使用RSA非对称加密的话,就很耗性能,影响用户体验)。
- 然后用非对称加密RSA来加密AES加密所使用的密钥key
- 最后把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加密,设置了填充方式与初始向量,交流后发现我们呢后台使用Java
的AES
加密,他们说找不到设置这两项的方法(我这里觉得肯定是可以设置),没办法,只好没有设置初始向量以及填充方式设置为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代码下载