zoukankan      html  css  js  c++  java
  • iOS AES-CBC、AES-ECB 加解密

    简介

    AES是加密的算法,使用128、192 和 256 位密钥,将被加密数据划分为128位(16字节)一块,然后使用某种加密模式进行加密
    
    关键词:
    块大小:16字节
    密钥长度:AES算法下,key的长度有三种:128、192和256 bits。
    加密模式:AES属于块加密(Block Cipher),块加密中有CBC、ECB、CTR、OFB、CFB等几种工作模式。
    填充模式:
    NoPadding,数据长度不对齐时使用""填充,否则不填充
    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
    ",remain);
        for(i=0; i<remain; i++)
        {
            str[len+i] = remain;
            //printf("str[len+i]= %d
    ",str[len+i]);
        }
           str[len+i] = '';
        
        return len + remain;
    }
    /**********************************************************
    函数名:DePKCS7Padding
    参数:unsigned char *p    --字符串地址
    返回值:int               --反填充个数
    说明:对明文进行PKCS7Padding填充反填充(去除后面的填充乱码)
    ***********************************************************/
    int DePKCS7Padding(unsigned char *str)
    {
          int remain,i;
          while (*str != ''){str++;}  //定位到
          str--;
          remain = *str;//读取填充的个数
          //printf("remain = %d
    ",remain);
          //定位到最前面的填充数
          for(i=0;i<remain;i++){str--;}
          str++;
          *str = '';//截断
          return remain;
    }
    /**********************************************************
    函数名:getlen
    参数:char *result        --字符串地址
    返回值:int                --字符串长度
    说明:                    --获取字符串长度
    ***********************************************************/
    int getlen(unsigned char *result){
        int i = 0;
        while (result[i] != ''){
            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,'', 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的代码注释了。可自行解开注释得到此模式的加解密代码。

  • 相关阅读:
    git学习笔记
    ubuntu常用命令
    hdfs[命令] fsck
    hdfs[命令] dfsadmin
    hdfs[命令] dfs
    Hadoop2.0新特性-持续追加【干货】
    Cloudera 建议使用 NTP 使 Hadoop 群集实现时间同步
    Cloudera CDH5 部署实战指南(离线安装)
    没有用户画像,别谈精准营销
    用户画像数据建模方法
  • 原文地址:https://www.cnblogs.com/xiongwj0910/p/11822041.html
Copyright © 2011-2022 走看看