心急的童鞋直接看这里Demo 运行之后可以去在线加密网站验证
AES(Advanced Encryption Standard)高级加密标准,又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES
AES的五种加密模式
AES有五种加密模式(CBC、ECB、CTR、OCF、CFB)
1.电码本模式(Electronic Codebook Book (ECB)
2.密码分组链接模式(Cipher Block Chaining (CBC))
3.计算器模式(Counter (CTR))
4.密码反馈模式(Cipher FeedBack (CFB))
5.输出反馈模式(Output FeedBack (OFB))
在iOS用到的一般就是ECB和CBC两种。
ECB-电码本模式
ECB是最简单的块密码加密模式,加密前根据加密块大小(AES加密块固定为128位)分成若干块,之后将每块使用相同的密钥单独加密,所以加密块相同的明文会生成相同的密文。
CBC-密码分组链接模式
CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。
OK,最简单的理论理解了,就来看iOS最重要的干货:加解密函数CCCrypt
CCCrypt - 加解密函数
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)
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)
重要的参数说明:
- CCOperation op:加密kCCEncrypt,解密kCCDecrypt
- CCAlgorithm alg:加密算法,这里kCCAlgorithmAES128和kCCAlgorithmAES是一样的,AES加密块固定是128位,咱们常说的AES128、192、256加密只是加密秘钥的长度不同(当然加密处理轮数也不同,这里就不做说明了)
- CCOptions options:
kCCOptionPKCS7Padding:填充模式
kCCOptionECBMode:ECB模式 - size_t keyLength:参数是下面这些,看到很多博客不管是128还是256,这里都写kCCBlockSizeAES128,这是不对的,这样加密出来的其实还是128加密
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, };
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, };
- iv:偏移向量,CBC模式下需要,不传默认16位0,ECB不需要
关于CCCrypt中的key和keyLength
AES数据块长度为128位,所以IV长度需要为16个字符(ECB模式不用IV),密钥根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充'\0'补足
key和keyLength之间的关系,现在算是搞明白了,key就是咱们传入的密钥,keyLength是决定密钥长度的,也就是aes128,192,256的真正区别了,如果传入的key是32位,也就是256要求的位数,但是keyLength选择了kCCKeySizeAES128,那么真正的key其实是截取前面的16位,如果key传入16位,但是keyLength选择了kCCKeySizeAES256,那就是密钥位数不够,会自动补全到32位
虽然密钥长度不够的话会自动补齐或者截取,不过感觉还是传入正确的密钥比较好,128的keysize=16,192keysize=24,256keysize=32
好了,直接上代码
Demo 需要引入 #import <CommonCrypto/CommonCrypto.h>
AES256 ECB模式加密
+(NSData *)dataByAes256ECB:(NSData *)data key:(NSString *)key mode:(CCOperation)operation {
char keyPtr[kCCKeySizeAES256 + 1];//选择aes256加密,所以key长度应该是kCCKeySizeAES256,32位 bzero(keyPtr, sizeof(keyPtr));//清零 [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];//秘钥key转成cString NSUInteger dataLength = data.length; size_t bufferSize = dataLength + kCCBlockSizeAES128; void * buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(operation, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode,//ECB模式 keyPtr, kCCKeySizeAES256, NULL,//选择ECB模式,不需要向量 data.bytes, dataLength, buffer, bufferSize, &numBytesDecrypted); if (cryptStatus == kCCSuccess) { NSData * result = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; return result; } free(buffer); return nil; }
AES128 CBC模式加解密
+(NSData *)dataByAes128CBC:(NSData *)data key:(NSString *)key mode:(CCOperation)operation iv:(NSString *)iv {
char keyPtr[kCCKeySizeAES128 + 1]; bzero(keyPtr, sizeof(keyPtr)); [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = data.length; size_t bufferSize = dataLength + kCCBlockSizeAES128; void * buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; NSString * initIv = iv; char ivPtr[kCCBlockSizeAES128+1]; memset(ivPtr, 0, sizeof(ivPtr)); [initIv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding]; CCCryptorStatus cryptStatus = CCCrypt(operation, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES128, ivPtr, data.bytes, dataLength, buffer, bufferSize, &numBytesDecrypted); if (cryptStatus == kCCSuccess) { NSData * result = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; return result; } free(buffer); return nil; }
在线验证