zoukankan      html  css  js  c++  java
  • iOS CommonCrypto 对称加密 AES ecb,cbc

    CommonCrypto 为苹果提供的系统加密接口,支持iOS 和 mac 开发;

    不仅限于AES加密,提供的接口还支持其他DES,3DES,RC4,BLOWFISH等算法,

    本文章主要讨论AES在iOS的处理,从接口资料描述和测试来看CommonCrypto 与AES相关的一些小结,

    • 支持的AES key size 有 128位,192位,256位
    • 目前仅支持 AES 128位 blocks 分组
    • 数据填充方式:Nopadding,PKCS7 两种
    • 分组模式:cbc,ecb 两种默认为 cbc 

    #import <CommonCrypto/CommonCryptor.h>

    1. 主要接口CCCrypt 

    /*!
        @function   CCCrypt
        @abstract   一个接口来处理加密解密方式.
                    还可以使用方式二:下面会有示例说明 ,调用流程分几步 ,CCCrytorCreate(),
                    CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().
        
        @param      alg             加解密使用的算法.
        
        
        @param      op              操作类型解密或解密: kCCEncrypt or
                        kCCDecrypt.
        
        @param      options         填充方式式通常是kCCOptionPKCS7Padding,默认分组模式cbc,.
        
        @param      key             密钥. 
        
        @param      keyLength       密钥长度.
        
        @param      iv              加密使用的向量参数,cbc模式需要,16个字节,ecb模式不需要,. 
        
        @param      dataIn          输入的数据. 
        
        @param      dataInLength    输入的数据长度.
        
        @param      dataOut         输出的数据. 
        
        @param      dataOutAvailable 输出数据时需要的可用空间大小.  
        
        @param      dataOutMoved    成功之后实际占用的空间大小. 
            
        @result     结果在为CCCryptorStatus 枚举
     */
        
    CCCryptorStatus CCCrypt(
        CCOperation op,         /* kCCEncrypt, 等. */
        CCAlgorithm alg,        /* kCCAlgorithmAES128, 等. */
        CCOptions options,      /* kCCOptionPKCS7Padding, 等. */
        const void *key,
        size_t keyLength,
        const void *iv,         /* 可选的向量 */
        const void *dataIn,     /*输入*/
        size_t dataInLength,
        void *dataOut,          /* 输出 */
        size_t dataOutAvailable,
        size_t *dataOutMoved)

    如下的封装调用方式,可以根据需要修改

     AES_256_cbc 加密或解密

    NSData *aes_cbc_256(NSData *inData,NSData *key,CCOperation coType)
    {
        NSData *retData = nil;
        if (!inData || !key) {
            return nil;
        }
        
        if (key.length!=32) {
            return nil;
        }
    
        
        NSUInteger dataLength = [inData length];
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc(bufferSize);
        size_t numBytesEncrypted = 0;
        CCCryptorStatus cryptStatus;
        
      //ecb 模式不需要使用 iv,cbc模式需要,当cbc模式时,如果不传iv,则默任全0 Byte iv[
    16] = {0}; for (int i = 0; i < 16; i++) { iv[i] = 1; } //加密 if (coType==kCCEncrypt) { cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,//使用AES算法 kCCOptionPKCS7Padding, key.bytes, kCCKeySizeAES256, iv, [inData bytes], dataLength, buffer, bufferSize, &numBytesEncrypted); } //解密 else if(coType ==kCCDecrypt) { cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, key.bytes, kCCKeySizeAES256, iv, [inData bytes], dataLength, buffer, bufferSize, &numBytesEncrypted); } if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return retData; }

    测试:

            Byte bkey[32] = {0};
            for (int i = 0; i < 32; i++) {
                bkey[i] = 8;
            }
            NSData *dkey = [NSData dataWithBytes:bkey length:32];
            NSLog(@"key:%@",dkey);
            
            NSString *srcStr = @"this is test hello string";
            NSData *srcData = [srcStr dataUsingEncoding:NSASCIIStringEncoding];
            NSLog(@"src:%@",srcData);
            NSData *encData = aes_cbc_256(srcData, dkey, kCCEncrypt);
            NSLog(@"enc:%@",encData);
            
            NSData *decData = aes_cbc_256(encData, dkey, kCCDecrypt);
            NSLog(@"dec:%@",decData);
            
            if (memcmp(srcData.bytes, decData.bytes, srcData.length)==0) {
                NSLog(@"test PASS");
            }
            else
            {
                NSLog(@"NO PASS");
            }

     输出日志

    2016-12-09 16:25:09.781 TestCrypt[2384:170598] key:<08080808 08080808 08080808 08080808 08080808 08080808 08080808 08080808>
    2016-12-09 16:25:09.782 TestCrypt[2384:170598] src:<74686973 20697320 74657374 2068656c 6c6f2073 7472696e 67>
    2016-12-09 16:25:09.782 TestCrypt[2384:170598] enc:<45430426 f51ac83c bd687f22 d9591dfe e413a769 89b07c41 b047d061 8e0a590c>
    2016-12-09 16:25:09.782 TestCrypt[2384:170598] dec:<74686973 20697320 74657374 2068656c 6c6f2073 7472696e 67>
    2016-12-09 16:25:09.782 TestCrypt[2384:170598] test PASS

    2. 另外 为了测试,在mac下安装了openssl 1.1.0c的库

    在终端下使用 openssl 命令来配合测试,

     在终端下openssl 命令加密数据,在ios上解密

     在ios上加密数据,在mac终端下使用openssl 命令解密

    配合测试的流程如上,我已在本机测试,不在这里贴示例了,说下openssl的命令吧

    主要使用openssl enc 命令,如下命令的帮助,其中部分用中文备注了

    Valid options are:
     -help          查看帮助-ciphers       查看算法列表
     -in infile     输入文件
     -out outfile   输出结果文件
     -pass val      密钥的密码
     -e             加密
     -d             解密
     -p             打印key和iv-P             打印key和iv并退出,这个是大写,实测不会生成out,用上面的小写-v             Verbose output
     -nopad         Disable standard block padding
     -salt          Use salt in the KDF (default)
     -nosalt        Do not use salt in the KDF
     -debug         Print debug info
     -a             Base64 encode/decode, depending on encryption flag
     -base64        Same as option -a
     -A             Used with -[base64|a] to specify base64 buffer as a single line
     -bufsize val   Buffer size
     -k val         Passphrase
     -kfile infile  Read passphrase from file
     -K val         密钥key,16进制-S val         Salt, in hex
     -iv val        向量iv,16进制-md val        Use specified digest to create a key from the passphrase
     -none          Don't encrypt
     -*             Any supported cipher
     -engine val    Use engine, possibly a hardware device

    如配合上面测试的 aes_256_cbc 方式,使用上面的密钥和key

    加密:

    openssl enc -aes-256-cbc -e -K 0808080808080808080808080808080808080808080808080808080808080808 -iv 01010101010101010101010101010101 -in srcTest.txt -out enc.txt -p

    解密:

    openssl enc -aes-256-cbc -d -K 0808080808080808080808080808080808080808080808080808080808080808 -iv 01010101010101010101010101010101 -in enc.txt -out dec.txt -p

    3. 对称加密分步方式二

       主要接口

    //创建加密器CCCryptorRef
    CCCryptorStatus CCCryptorCreate( CCOperation op,
    /* kCCEncrypt, etc. */ CCAlgorithm alg, /* kCCAlgorithmDES, etc. */ CCOptions options, /* kCCOptionPKCS7Padding, etc. */ const void *key, /* raw key material */ size_t keyLength, const void *iv, /* optional initialization vector */ CCCryptorRef *cryptorRef) /* RETURNED */
    //获取输出数据的最大长度 size_t CCCryptorGetOutputLength( CCCryptorRef cryptorRef, size_t inputLength,
    bool final)
    //加密处理 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 */ //处理最后的数据块 CCCryptorStatus CCCryptorFinal( CCCryptorRef cryptorRef, void *dataOut, size_t dataOutAvailable, size_t *dataOutMoved) /* number of bytes written */
    //释放 CCCryptorStatus CCCryptorRelease( CCCryptorRef cryptorRef)

    如下封装示例调用

     aes_256_cbc 加密或解密

    NSData *TEST_AES(NSData *indata,CCOperation otype)
    {
        NSData *retData = nil;
    //测试的密钥或向量 Byte tkey[
    32] = {0}; for (int i = 0; i < 32; i++) { tkey[i] = 8; } Byte iv[16] = {0}; for (int i =0; i < 16; i++) { iv[i] = 1; } CCCryptorRef cryptor = NULL; CCCryptorStatus ccret;
      //创建加密解密器
    if (otype==kCCEncrypt) { ccret = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, tkey, kCCKeySizeAES256, iv, &cryptor); } else if (otype == kCCDecrypt) { ccret = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, tkey, kCCKeySizeAES256, iv, &cryptor); } if (ccret!=kCCSuccess) { return nil; } size_t bufsize = 0; size_t moved = 0; size_t total = 0;
      //获取最大长度 bufsize
    = CCCryptorGetOutputLength(cryptor, indata.length, true); char * buf = (char*)malloc(bufsize); bzero(buf, bufsize);
      //加解密 ccret
    = CCCryptorUpdate(cryptor, indata.bytes,indata.length, buf, bufsize, &moved); total += moved; if (ccret!=kCCSuccess) { return nil; }
      //处理最后的数据块 ccret
    = CCCryptorFinal(cryptor, buf+total, bufsize-total, &moved); if (ccret!=kCCSuccess) { return nil; } total +=moved; CCCryptorRelease(cryptor);
       retData
    = [NSData dataWithBytes:buf length:total]; free(buf); return retData; }

    测试使用

            NSString *srcStr = @"this is test hello string";
            NSData *srcData = [srcStr dataUsingEncoding:NSASCIIStringEncoding];
    
            NSData *encData = TEST_AES(srcData, kCCEncrypt);
            NSData *decData = TEST_AES(encData, kCCDecrypt);
            
            NSLog(@"src:%@",srcData);
            NSLog(@"enc:%@",encData);
            NSLog(@"dec:%@",decData);
    
            if (memcmp(srcData.bytes, decData.bytes, srcData.length)==0) {
                NSLog(@"PASS");
            }
            else
            {
                NSLog(@"NP_PASS");
            }

    输出日志

    2016-12-09 16:42:49.105 TestCrypt[2404:177716] src:<74686973 20697320 74657374 2068656c 6c6f2073 7472696e 67>
    2016-12-09 16:42:49.106 TestCrypt[2404:177716] enc:<45430426 f51ac83c bd687f22 d9591dfe e413a769 89b07c41 b047d061 8e0a590c>
    2016-12-09 16:42:49.106 TestCrypt[2404:177716] dec:<74686973 20697320 74657374 2068656c 6c6f2073 7472696e 67>
    2016-12-09 16:42:49.106 TestCrypt[2404:177716] PASS

    两种方式测试的结果一致;

    可见第一种方式其实是苹果内部对第二种方式进一步的封装处理。

    4. 总结:

        关于在iOS上的对称加密方式;

    • 使用本文苹果API,本文:http://www.cnblogs.com/cocoajin/p/6150203.html
    • 使用openssl ,见文章:http://www.cnblogs.com/cocoajin/p/6121706.html
    • 使用 Cryptopp,见文章:http://www.cnblogs.com/cocoajin/p/6112562.html

     封装工具:https://github.com/cocoajin/Security-iOS

  • 相关阅读:
    python微信机器人
    爬取糗事百科,微信自动发送
    验证码破解
    [Python]机器学习【推荐】
    [Python]利用jieba.analyse进行 关键词 提取
    《将博客搬至CSDN》
    [极限测试]第一日进度
    [Python]调用百度API进行自然语言处理 标签、关键字 以及 词法分析
    学习进度报告【第三周】
    [Python]调用百度地图API对地点进行搜索,利用 JSON 返回纬度/行政区域编号
  • 原文地址:https://www.cnblogs.com/cocoajin/p/6150203.html
Copyright © 2011-2022 走看看