在上一部分概述中概括介绍了CommonCrypto
中每个文件大致的内容,那么下面详细介绍第一个文件CommonCryptor的具体使用以及相关内容。示例代码请前往Github CommonCrypto下载。
CommonCryptor
苹果官方对CommonCryptor文件的描述是对称加密的通用接口,意味着接口中有着多种加密方法的选择,也就是文档中的CCAlgorithm
,它是这个样子的。(记录一下 Algorithm
译 算法)
CCAlgorithm
// Algorithm 以及 块加密 对于的块大小.
enum {
kCCAlgorithmAES128 = 0, // AES 对应 kCCBlockSizeAES128 = 16
kCCAlgorithmAES = 0, // 同上
kCCAlgorithmDES, // DES 对应kCCBlockSizeDES = 8
kCCAlgorithm3DES, //三重DES 对应kCCBlockSize3DES = 8
kCCAlgorithmCAST, //CAST 对应kCCBlockSizeCAST = 8
kCCAlgorithmRC4, //流加密
kCCAlgorithmRC2, //RC2
kCCAlgorithmBlowfish //Blowfish 对应kCCBlockSizeBlowfish = 8
};
typedef uint32_t CCAlgorithm;
还有对应的密匙长度.如下所示:
enum {
kCCKeySizeAES128 = 16,
kCCKeySizeAES192 = 24,
kCCKeySizeAES256 = 32,
kCCKeySizeDES = 8,
kCCKeySize3DES = 24,
kCCKeySizeMinCAST = 5,
kCCKeySizeMaxCAST = 16,
kCCKeySizeMinRC4 = 1,
kCCKeySizeMaxRC4 = 512,
kCCKeySizeMinRC2 = 1,
kCCKeySizeMaxRC2 = 128,
kCCKeySizeMinBlowfish = 8,
kCCKeySizeMaxBlowfish = 56,
};
同样,接口中有着加解密处理方式的选择->CCOperation
,分别为kCCEncrypt
加密以及kCCDecrypt
解密。
其次呢我们来介绍一下加解密常用到的函数,它们有两种使用的方式去获取加解密处理的数据。核心函数分别是
-
CCCrytorCreate() | CCCryptorCreateWithMode,CCCryptorUpdate() , CCCryptorFinal() , and CCCryptorRelease()
; -
CCCrypt()
。
第一种
通过CCCrytorCreate() | CCCryptorCreateWithMode(),CCCryptorUpdate() , CCCryptorFinal() and CCCryptorRelease()
;获取加解密数据
Create
苹果官方有提供了三种函数接口,它们分别是CCCryptorcreate()
、CCCryptorCreateFromData()
、以及CCCryptorCreateWithMode()
.下面主要讲解CCCryptorcreate()
以及CCCryptorCreateWithMode()
两种函数。
-
CCCrytorCreate()
CCCryptorCreate()
我的理解是快速创建的函数,默认是CBC模式下.可选ECB模式。以下是代码示例:
CCOperation operation = kCCEncrypt; //kCCEncrypt | KCCDecrypt 加密 | 解密
CCAlgorithm algorithm = kCCAlgorithmAES; // 算法以AES为例
CCOptions options = kCCOptionPKCS7Padding; // 填补方式以 kCCOptionPKCS7Padding 为例.若使用ECB模式,则为kCCOptionPKCS7Padding | kCCOptionECBMode.
// 生成一个长度16的密匙数据
NSData *keyData = [@"16TestEncryptKey" dataUsingEncoding:NSUTF8StringEncoding];
// 生成一个长度16的向量数据,若不生成可传NULL,苹果文档有这样一段话 If CBC mode is selected and no IV is provided, an IV of all zeroes will be used.指出在CBC模式下,如果没有提供IV向量,则默认使用字节全为0x00的一个IV向量。
NSData *ivData = [@"16TestEncryptIv" dataUsingEncoding:NSUTF8StringEncoding];
if (algorithm == kCCAlgorithmAES) {
// 若密匙长度大于16小于24,则判断值应为kCCKeySizeAES192.
if (keyData.length < kCCKeySizeAES128) {
//两种处理办法
//1.补足位数.
NSMutableData *handleData = keyData.mutableCopy;
[handleData setLength:kCCKeySizeAES128];
keyData = handleData;
//2.返回加密失败.
NSLog(@"密匙长度不足16位");
return;
}
}
// 声明 CCCryptoRef 用于返回结果数据.
CCCryptorRef cryptorRef;
// 1.create创建的第一种函数.
// CCCryptorCreate()函数通过指定加解密、算法、默认CBC模式、密匙长度和密匙字节及向量字节返回一个CCCryptorRef的对象
CCCryptorStatus status = CCCryptorCreate(operation, algorithm, options, keyData.bytes, keyData.length, ivData.bytes, &cryptorRef);
if ( status != kCCSuccess )
{
NSLog(@"失败原因%d",status);
}
-
CCCryptorCreateWithMode()
CCCryptorCreateWithMode()
可以选择加密模式、以及填补模式。以下是代码示例:
//参数生成同上, 以下是额外参数生成
CCMode mode = kCCModeCBC; // 可选加密模式 CBC、EBC,官方提供的文档还可以选择CFB、CTR、 OFB、XTS等.
CCPadding padding = ccPKCS7Padding; //填补模式 ccPKCS7Padding、ccNoPadding.
// 2.create创建第二种函数
//CCCryptorCreateWithMode()函数通过指定加解密、模式、算法、填充模式、密匙长度和密匙字节及向量字节返回一个CCCryptorRef的对象.tweak key以及tweak key length默认可以设置为0,在XTS模式下才会用到
CCCryptorStatus status =CCCryptorCreateWithMode(operation, mode, algorithm, padding, ivData.bytes, keyData.bytes, keyData.length, NULL, 0, 0, 0, &cryptorRef);
if ( status != kCCSuccess )
{
NSLog(@"失败原因%d",status);
}
我们会发现,苹果仅提供了PKCS7一种填充方式,这有可能在极少的特殊情况下给我们带来不方便。其实我们可以使用该函数设置填充模式为ccNoPadding
并在这之前自己完成对数据的填补操作,例如ANSIX923
、ISO10126
等,当然有想详细了解的可以去我的另外一篇文章实现iOS下对称加密多种填充方式中阅读。
同样的,在代码段最后一部分,有一个CCCryptorStatus
状态。关于CCCryptorStatus
,它是一个状态枚举值,可以根据结果值判断是否成功。返回结果如下所示,
enum {
kCCSuccess = 0, //成功
kCCParamError = -4300,
kCCBufferTooSmall = -4301,
kCCMemoryFailure = -4302,
kCCAlignmentError = -4303,
kCCDecodeError = -4304,
kCCUnimplemented = -4305,
kCCOverflow = -4306,
kCCRNGFailure = -4307,
kCCUnspecifiedError = -4308,
kCCCallSequenceError= -4309,
kCCKeySizeError = -4310,
};
Update和GetOutputLength
接下来就是加密的处理部分了,苹果官方说明CCCryptorUpdate()
函数用于处理(加密,解密)数据,如果有结果的话,写入开发者提供的缓冲区。以下是Updata
函数的参数介绍
CCCryptorStatus CCCryptorUpdate(
CCCryptorRef cryptorRef,
const void *dataIn,
size_t dataInLength,
void *dataOut, /* data RETURNED here */
size_t dataOutAvailable,
size_t *dataOutMoved) /* number of bytes written */
通过阅读苹果文档会得知,cryptorRef
是通过CCCryptorCreate()函数获取的,而dataOut指针
及下面的dataOutAvailable
和dataOutMoved
参数是通过CCCryptorGetOutputLength()
函数获取的。所以需要先通过GetOutputLength()
函数和需要加密的输入数据计算获取到输出字节的大小,malloc
一块空间,并将地址指针作为参数用于函数输出数据写入缓冲区。以下是代码实例:
//确定处理给定输入所需的输出缓冲区大小尺寸。
size_t bufsize = CCCryptorGetOutputLength( cryptorRef, (size_t)[self length], true );
void * buf = malloc( bufsize );
size_t bufused = 0;
size_t bytesTotal = 0;
//调用Update函数,处理(加密,解密)一些数据。如果有结果的话,写入提供的缓冲区.
status = CCCryptorUpdate( cryptorRef, [self bytes], (size_t)[self length],buf, bufsize, &bufused );
if ( status != kCCSuccess )
{
free( buf );
NSLog(@"失败原因%d",status);
return
}
bytesTotal += bufused;
Final 和 Release
最后就是结果处理以及释放对象的操作了,这需要用到CCCryptorFinal()
和CCCryptorRelease()
两个函数。苹果官方指出CCCryptorFinal()
函数用于完成加密或解密操作,并获得(可能的)最终数据输出。
并且在介绍中说到,如果在执行对称加解密的时候并没有使用填补或者进行流加密操作时,可以不调用CCCryptorFinal()
函数。所以我的猜测是该函数主要功能是用于对加解密的数据进行检测可能存在的填充字段,并将其去除。
CCCryptorRelease()
函数则用于释放CCCryptorRef对象。以下是代码实例:
// From Brent Royal-Gordon (Twitter: architechies):
// Need to update buf ptr past used bytes when calling CCCryptorFinal()
status = CCCryptorFinal( cryptorRef, buf + bufused, bufsize - bufused, &bufused );
if ( status != kCCSuccess )
{
free( buf );
NSLog(@"失败原因%d",status);
return nil;
}
bytesTotal += bufused;
NSData *result = [NSData dataWithBytesNoCopy:buf length: bytesTotal];
CCCryptorRelease( cryptorRef);
第二种
CCCryptor
先来一段CCCryptor()
函数声明的内容.
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)
通过上述内容可以看出,CCCryptor()
函数其实是基于第一种模式下的二次封装,是一个单次执行加解密操作的函数。不用详细介绍了,如果仅有简单需求的小伙伴们可以使用这个函数,直接上一段简单的代码实例。
- (NSData *)encryptWithAlgorithm:(CCAlgorithm)algorithm Key:(NSData *)key iv:(NSData *)iv {
CCOptions options = kCCOptionECBMode | kCCOptionPKCS7Padding;
//options = kCCOptionPKCS7Padding;
int blockSize = (algorithm == kCCAlgorithmAES) ? 16 : 8 ;
NSData *result = nil;
size_t bufferSize = self.length + blockSize;
void *buffer = malloc(bufferSize);
if (!buffer) return nil;
size_t encryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
algorithm,
options,
key.bytes,
key.length,
iv.bytes,
self.bytes,
self.length,
buffer,
bufferSize,
&encryptedSize);
if (cryptStatus == kCCSuccess) {
result = [[NSData alloc]initWithBytes:buffer length:encryptedSize];
free(buffer);
return result;
} else {
free(buffer);
return nil;
}
}
关于CommonCryptor这份文件大致内容就是这些了,由于完整代码内容过长,有小伙伴们如果想查看相关代码的,请前往Github CommonCrypto下载。
如果想了解MD5
、SHA1
等哈希摘要算法 以及HMAC
使用的话,可以阅读iOS 关于CommonCrypto 框架③(MD5、SHA1以及HMAC_SHA1 等哈希摘要)。