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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM