前语
在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));
-
CCOperation
:kCCEncrypt
加密,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
:加密形式
ECB
:kCCOptionPKCS7Padding | kCCOptionECBMode
CBC
:kCCOptionPKCS7Padding
enum {
/* options for block ciphers */
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
/* stream ciphers currently have no options */
};
typedef uint32_t CCOptions;
-
key
:密钥 -
keyLength
:密钥长度 -
iv
:iv
初始化向量,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;
}