注册
iOS

iOS 开发中的AES加密

前言


在iOS的日常开发中,特别是设计网络请求时,会用到加密算法,例如在客户端需要发起一个HTTP请求给服务端,其中会传递一些参数,为了防止参数在网络传输过程中被窃取或者篡改,我们就需要使用一些加密算法来对请求参数加密和签名。今天就重点介绍一下AES和HMAC_SHA256两个算法,因为服务端大多数都是使用java语言来编写,AES算法在iOS的Objective-C中和java的实现有些差异,本文重点介绍AES在iOS开发中的应用和需要注意的事项。


AES 加密算法简介


AES是一种典型的对称加密/解密算法,使用加密函数和密钥来完成对明文的加密,然后使用相同的密钥和对应的函数来完成解密。AES的优点在于效率非常高,相比RSA要高得多。AES共有ECB、CBC、CFB和OFB四种加密模式。


在iOS中的实现


Objective-C中支持AES的ECB和CBC两种模式。
1、电码本模式(Electronic Codebook Book (ECB))
这种模式主要是将明文划分为几个明文段,分块加密,但是加密密钥是相同的。
2、密码分组链接模式(Cipher Block Chaining (CBC))
这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。


ECB是最简单的一种模式,只需要传入待加密的内容和加密的key即可。(一般不推荐ECB模式)
CBC的特点是,除了需要传入加密的内容和加密的key,还需要传入初始化向量iv。即使每次加密的内容和加密的key相同,只要调整iv就可以让最终生成的密文不同。
在客户端和服务端之间传输数据一般是使用约定好的key对指定参数做AES的CBC加密,初始化向量可以随机动态生成,最终将生成好的密文和随机向量iv拼接在一起传给服务端。如:iv+密文。
iv是指定的长度如16位,这样服务端拿到客户端传输过来的数据可以先取前16位作为iv,剩余的是需要解析的密文。这么做大大提升了数据的安全性和破解难度。即使相同的带加密参数,因为有随机向量的参入,最终生成的密文也不相同。


iOS中一般使用#import <CommonCrypto/CommonCryptor.h>库中的这个函数:

CCCryptorStatus CCCrypt(
CCOperation op, /* kCCEncrypt, etc. */
CCAlgorithm alg, /* kCCAlgorithmAES128, etc. */
CCOptions options, /* kCCOptionPKCS7Padding, etc. */
const void *key,
size_t keyLength,
const void *iv, /* optional initialization vector */
const void *dataIn, /* optional per op and alg */
size_t dataInLength,
void *dataOut, /* data RETURNED here */
size_t dataOutAvailable,
size_t *dataOutMoved)
API_AVAILABLE(macos(10.4), ios(2.0));
  • CCOperationkCCEncrypt 加密,kCCDecrypt 解密
enum {
kCCEncrypt = 0,
kCCDecrypt,
};
typedef uint32_t CCOperation;
  • CCAlgorithm:加密算法、默认为AES
enum {
kCCAlgorithmAES128 = 0, /* Deprecated, name phased out due to ambiguity with key size */
kCCAlgorithmAES = 0,
kCCAlgorithmDES,
kCCAlgorithm3DES,
kCCAlgorithmCAST,
kCCAlgorithmRC4,
kCCAlgorithmRC2,
kCCAlgorithmBlowfish
};
typedef uint32_t CCAlgorithm;

  • CCOptions:加密模式
    ECBkCCOptionPKCS7Padding | kCCOptionECBMode
    CBCkCCOptionPKCS7Padding
enum {
/* options for block ciphers */
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
/* stream ciphers currently have no options */
};
typedef uint32_t CCOptions;

  • key:密钥
  • keyLength:密钥长度
  • iviv 初始化向量,ECB 不需要。iv定长所以不需要长度(8字节)。
  • dataIn:加密/解密的数据
  • dataInLength:加密/解密的数据长度
  • dataOut:缓冲区(地址),存放密文/明文
  • dataOutAvailable:缓冲区大小
  • dataOutMoved:加密/解密结果大小

封装如下:

/**
* 解密字符串
*
* @param string 加密并base64编码后的字符串
* @param keyString 解密密钥
* @param iv 初始化向量(8个字节)
*
* @return 返回解密后的字符串
*/
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {

// 设置秘钥
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];

// 设置iv
uint8_t cIv[self.blockSize];
bzero(cIv, self.blockSize);
int option = 0;
if (iv) {
[iv getBytes:cIv length:self.blockSize];
option = kCCOptionPKCS7Padding;//CBC 加密!
} else {
option = kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密!
}

// 设置输出缓冲区
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);

// 开始解密
size_t decryptedSize = 0;

CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&decryptedSize);

NSData *result = nil;
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
} else {
free(buffer);
NSLog(@"[错误] 解密失败|状态编码: %d", cryptStatus);
}

return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}

上文提到使用CBC模式,可以创建一个随机的iv:

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>

NSData *generateRandomIV(size_t length) {
NSMutableData *randomIV = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault, length, randomIV.mutableBytes);

if (result == errSecSuccess) {
return randomIV;
} else {
// 处理生成随机IV失败的情况
return nil;
}
}

int main(int argc, const char * argv[]) {
@autoreleasepool {
// 设置AES加密参数
NSData *key = [@"YourAESKey123456" dataUsingEncoding:NSUTF8StringEncoding];
size_t ivLength = kCCBlockSizeAES128; // IV长度为16字节(AES-128)

// 生成随机IV
NSData *randomIV = generateRandomIV(ivLength);

if (randomIV) {
// 使用randomIV进行AES加密
// 这里你可以调用相应的加密方法,传入randomIV作为IV参数
// 例如,使用CommonCrypto库进行AES加密
// 具体实现将取决于你所使用的加密库和算法

// 示例:在这里调用AES加密函数,传入key和randomIV
// ...
} else {
NSLog(@"生成随机IV失败");
}
}
return 0;
}

作者:lefht0pz408mdl7yvptpm23ci
链接:https://juejin.cn/post/7273674732448792639
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册