AES(Advanced Encryption Standard)是一种对称加密算法,给定一个密钥可以将普通文本转换为密文。通过相同的密钥将密文还原为原始文本。AES 提供了三种密钥的长度 128,192和256, 在 iOS设备上支持硬件优化,速度是非常快的。

基本知识

密钥

我们需要一开始就分清楚密钥(Key)和密码(password)的区别,通过 PBKDF2 (Password-Based Key Derivation Fuction)可以将密码转换为密钥。使用 PBKDF2 需要生成一个很大的随机数( salt ),通过执行若干次 PBKDF2 生成密钥。Rfc2898 PKCS#5标准是执行1000次。

分组填充

AES 是分组加密,每次处理128位(16字节)的输入,但是很多事实加密的数据都不是16字节长度,也可能不是16字节长度的整数倍,因此还需要进行填充,比较最后一个分组是15个字节,会追加0x01的字节,如果是14个字节,会最佳两个值为0x02的字节。iOS中支持PKCS #7填充方式,在iOS的选项是 kCCOptionPKCS7Padding

初始化向量

初始化向量可选,如果不提供值,默认是全是0的分组。在Rfc2898 标准中初始化向量长度是 AES128。默认生成(32+16)长度的密钥,取前32的长度作为key,后16长度作为iv。

###实现
引用 <CommonCrypto/CommonCrypto.h>,密钥以及向量生成流程如下

代码如下

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
+ (void)deriveBytes:(NSMutableData *)deriveBytes fromPassword:(NSString *)password andSalt:(NSData *)salt{



[deriveBytes setLength:(kCCKeySizeAES256+kCCBlockSizeAES128)];

int result = CCKeyDerivationPBKDF(kCCPBKDF2,
password.UTF8String,
[password lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
salt.bytes,
salt.length,
kCCPRFHmacAlgSHA1,
rounds,
deriveBytes.mutableBytes,
(kCCKeySizeAES256+kCCBlockSizeAES128));



if (result != kCCSuccess) {
NSLog(@"can't generate the AES derivedKey");
return;
}



}

生成加密用的 keyiv后便可使用 CCCryptorCreate 先生成一个加密器,然后算出加密后的长度,使用CCCrypt可以快速加密。解密的代码只差一个CCOperation

加密代码如下

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
37
38
39
40
- (NSData *)aesEncryptWithKey:(NSData *)key andIV:(NSData *)iv{
CCCryptorRef __cryptor;

CCCryptorStatus
cryptorStatus = CCCryptorCreate(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
iv.bytes,
&__cryptor);

if (cryptorStatus != kCCSuccess) {
NSLog(@"can't generate the AES cryptor");
return nil;
}

NSMutableData *outdata = [NSMutableData dataWithLength:[self length]];
[outdata setLength:CCCryptorGetOutputLength(__cryptor, [self length], true)];


NSMutableData *buffer = outdata;
size_t dataOutMoved;

CCCryptorStatus cryptStatuslast = CCCrypt(kCCEncrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
iv.bytes,
self.bytes,
self.length,
outdata.mutableBytes,
outdata.length, &dataOutMoved);
if (cryptStatuslast == kCCSuccess) {
return [buffer subdataWithRange:NSMakeRange(0, dataOutMoved)];
}else{
return nil;
}
}

我仿照Java的Rfc2898DeriveBytes类实现了一套oc的code放在gitHub了有需要的朋友可以看看。