iOS AES-CBC、AES-ECB 加解密

簡介

AES是加密的算法,使用12八、192 和 256 位密鑰,將被加密數據劃分爲128位(16字節)一塊,而後使用某種加密模式進行加密

關鍵詞:
塊大小:16字節
密鑰長度:AES算法下,key的長度有三種:12八、192和256 bits。
加密模式:AES屬於塊加密(Block Cipher),塊加密中有CBC、ECB、CTR、OFB、CFB等幾種工做模式。
填充模式:
NoPadding,數據長度不對齊時使用"\0"填充,不然不填充
PKCS7Padding,假設數據長度須要填充n(n>0)個字節纔對齊,那麼填充n個字節,每一個字節都是n;若是數據自己就已經對齊了,則填充一塊長度爲塊大小的數據,每一個字節都是塊大小
PKCS5Padding,PKCS7Padding的子集,塊大小固定爲8字節。

AES加密,若是輸入是16*n字節,NoPadding填充的狀況下,輸出和輸入相同;有填充的狀況下,輸出是16*(n+1)。
若是輸入不是16字節整數倍,而是大於16*n小於16*(n+1),NoPadding填充狀況下(只能是CFB和OFB模式),輸出和輸入長度相同;其餘狀況下,輸出長度是16*(n+1)

iOS系統庫實現AES-CBC-PKCS7Padding 和 AES-ECB-PKCS7Padding

#import <CommonCrypto/CommonCrypto.h>
#import <CommonCrypto/CommonDigest.h>
//加密
+ (NSData *)encryptAES:(NSString *)content key:(NSString *)key {
    NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = contentData.length;
    // 爲結束符'\\0' +1
    char keyPtr[kCCKeySizeAES128 + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    // 密文長度 <= 明文長度 + BlockSize
    size_t encryptSize = dataLength + kCCBlockSizeAES128;
    void *encryptedBytes = malloc(encryptSize);
    size_t actualOutSize = 0;
    NSString *const kInitVector = @"1234567890123456"; //16位偏移,CBC模式纔有
    NSData *initVector = [kInitVector dataUsingEncoding:NSUTF8StringEncoding];
    CCCryptorStatus cryptStatus = CCCrypt(
    kCCEncrypt,//kCCEncrypt 表明加密 kCCDecrypt表明解密
    kCCAlgorithmAES,//加密算法
    kCCOptionPKCS7Padding,  // 系統默認使用 CBC,而後指明使用 PKCS7Padding,iOS只有CBC和ECB模式,若是想使用ECB模式,能夠這樣編寫  kCCOptionPKCS7Padding | kCCOptionECBMode
    keyPtr,//公鑰
    kCCKeySizeAES128,//密鑰長度128
    initVector.bytes,//偏移字符串
    contentData.bytes,//編碼內容
    dataLength,//數據長度
    encryptedBytes,//加密輸出緩衝區
    encryptSize,//加密輸出緩衝區大小
    &actualOutSize);//實際輸出大小
    if (cryptStatus == kCCSuccess) {
    // 返回編碼後的數據
    return [NSData dataWithBytesNoCopy:encryptedBytes length:actualOutSize];
    }
    free(encryptedBytes);
    return nil;
}
// 解密
+ (NSData *)decryptAESWithData:(NSData *)data key:(NSString *)key{
 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 *const kInitVector = @"1234567890123456"; //16位偏移,CBC模式纔有
 NSData *initVector = [kInitVector dataUsingEncoding:NSUTF8StringEncoding];
 //字段含義在上面加密已經解釋過了,這裏不作贅述
 CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, keyPtr, kCCBlockSizeAES128, initVector.bytes, [data bytes], dataLength, buffer, bufferSize, &numBytesDecrypted);

 if(cryptStatus == kCCSuccess){
 	return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
 }

 free(buffer);

 return nil;

}

OpenSSL庫AES-CBC-PKCS7Padding 和 AES-ECB-PKCS7Padding

//pod引入openssl庫
pod 'OpenSSL-Universal'
#import "crypto.h"
#import "evp.h"
#import "aes.h"
+ (NSData *)encryptStringWithString:(NSString *)string key:(NSString *)key{
    const char *p_str = [string cStringUsingEncoding:NSUTF8StringEncoding];
    const char *p_key = [key cStringUsingEncoding:NSUTF8StringEncoding];
    
    unsigned char *p_out = malloc(string.length + 16);
    memset(p_out, 0, string.length * 2);
    int result = aes_encrypt(p_str, (char *)p_key, (unsigned char *)p_out);
    
//    NSLog(@"result = %d enOut = %s",result,p_out);
    
    NSInteger len = getlen(p_out);
    NSData *data = [NSData dataWithBytes:p_out length:len];
    return data;
}
+ (NSData *)decryptDataWithData:(NSData *)data andKey:(NSString *)key{
    const char *p_key = [key cStringUsingEncoding:NSUTF8StringEncoding];
    unsigned char *p_out = malloc(data.length*2);
    memset(p_out, 0, data.length * 2);
    
    int result = aes_decrypt((const char *)data.bytes, (char *)p_key, p_out);
//    NSLog(@"result = %d deOut = %s",result,p_out);
    
    NSInteger len = getlen(p_out);
    NSData *dataOut = [NSData dataWithBytes:p_out length:len];
    return dataOut;
}
/**********************************************************
函數名:PKCS7Padding
參數:unsigned char *str      --字符串地址
返回值:int                   --正向測試填充後的字符串長度
說明:對初始數據進行PKCS7Padding填充
***********************************************************/
int PKCS7Padding(unsigned char *str){
    int remain, i;
    int len=getlen(str);
    remain = 16 - len%16;
    //printf("remain = %d\n",remain);
    for(i=0; i<remain; i++)
    {
        str[len+i] = remain;
        //printf("str[len+i]= %d\n",str[len+i]);
    }
       str[len+i] = '\0';
    
    return len + remain;
}
/**********************************************************
函數名:DePKCS7Padding
參數:unsigned char *p    --字符串地址
返回值:int               --反填充個數
說明:對明文進行PKCS7Padding填充反填充(去除後面的填充亂碼)
***********************************************************/
int DePKCS7Padding(unsigned char *str)
{
      int remain,i;
      while (*str != '\0'){str++;}  //定位到\0
      str--;
      remain = *str;//讀取填充的個數
      //printf("remain = %d\n",remain);
      //定位到最前面的填充數
      for(i=0;i<remain;i++){str--;}
      str++;
      *str = '\0';//截斷
      return remain;
}
/**********************************************************
函數名:getlen
參數:char *result        --字符串地址
返回值:int                --字符串長度
說明:                    --獲取字符串長度
***********************************************************/
int getlen(unsigned char *result){
    int i = 0;
    while (result[i] != '\0'){
        i++;
    }
    return i;
}

/**********************************************************
函數名:aes_encrypt
參數:const char* str_in        --輸入字符
參數:unsigned char* key        --key
參數:unsigned char* out        --輸出字符
返回值:int                      --0失敗  1成功
說明:加密
***********************************************************/
int aes_encrypt(const char* str_in, char* key, unsigned char* out)
{
    OPENSSL_cleanse(NULL, 0);
    if (!str_in || !key || !out) return 0;

    //加密的初始化向量
    unsigned char iv[AES_BLOCK_SIZE];

    //16位密碼
    char tmpIV[] = "1234567890123456";
    for (int i = 0; i < 16; ++i)
        iv[i] = tmpIV[i];

    AES_KEY aes;
    if (AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return 0;
    }

    //
    size_t len = strlen(str_in);
    unsigned char *aes_encode_temp = malloc(len + 16);
    memset(aes_encode_temp,'\0', len + 16);
    memcpy(aes_encode_temp, str_in, len);
    
    len = PKCS7Padding(aes_encode_temp);
    AES_cbc_encrypt((unsigned char*)aes_encode_temp, (unsigned char*)out, len, &aes, iv, AES_ENCRYPT);
    
//    for (int nIndex = 0; nIndex < getlen((char *)str_in); nIndex += 16) {
//        AES_ecb_encrypt((unsigned char*)str_in + nIndex, (unsigned char*)out + nIndex,&aes,AES_ENCRYPT);
//    }
    
    return 1;
}

/**********************************************************
函數名:aes_decrypt
參數:const char* str_in        --輸入
參數:unsigned char* key        --key
參數:unsigned char* out        --輸出
返回值:int                  --0失敗  1成功
說明:                --解密
***********************************************************/
int aes_decrypt(const char* str_in, char* key,unsigned char* out)
{
    OPENSSL_cleanse(NULL, 0);
    if (!str_in || !key || !out) return 0;
    unsigned char iv[AES_BLOCK_SIZE];//加密的初始化向量
    char tmpIV[] = "1234567890123456";
    for (int i = 0; i < 16; ++i)
        iv[i] = tmpIV[i];

    AES_KEY aes;
    if (AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return 0;
    }

    size_t len = strlen(str_in);
    
//    for (int nIndex = 0; nIndex < getlen((char *)str_in); nIndex += 16) {
//        AES_ecb_encrypt((unsigned char*)str_in + nIndex, (unsigned char*)out + nIndex,&aes,AES_DECRYPT);
//    }
    AES_cbc_encrypt((unsigned char*)str_in, (unsigned char*)out, len, &aes, iv, AES_DECRYPT);
    DePKCS7Padding(out);
    
    return 1;
}

上述代碼中,把AES-CBC-PKCS7的代碼註釋了。可自行解開註釋獲得此模式的加解密代碼。算法

相關文章
相關標籤/搜索