• iOS开发——AES加密(128 CBC/ECB NoPadding/PKCS7Padding)


      项目开发过程中,经常会使用各种加密手段来保证数据的安全性,常见的有MD5,DES,AES等等。摘取百度百科AES词条的简介:AES即高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

      以上可见AES作为一项加密技术使用是很普遍的,博主之前的一个项目跟后台交换数据时就需要使用到AES 128 ECB NoPadding加密,但是苦于网上的关于AES的博客内容大同小异,基本都是AES 128 CBC NoPadding加密,所以纠结了很久。从网上下载下来的AES 128 CBC NoPadding加密方法针对后台数据的加密解密失灵时不灵(后台是ECB模式)。后来自己鼓捣了很长时间总算是弄出来了,网上档下来的方法可以使用,不过需要修改部分代码,让我们先看看网上比较多的AES 128 CBC NoPadding的方法(方法来自博客:http://www.cnblogs.com/wanyakun/p/3403352.html)。

      首先,.h文件:

    #import <Foundation/Foundation.h>
    
    @interface AESEnrypt : NSObject
    
    + (NSString*) AES128Encrypt:(NSString *)plainText;
    
    + (NSString*) AES128Decrypt:(NSString *)encryptText;
    
    @end
    

      然后是.m文件:

    #import "AESEncrypt.h"
    #import <CommonCrypto/CommonCryptor.h>
    #import "GTMBase64.h"
    
    #define gkey @"16位长度的字符串" //自行修改
    #define gIv @"16位长度的字符串" //自行修改
    
    @implementation AESEncrypt
    
    +(NSString *)AES128Encrypt:(NSString *)plainText
    {
        char keyPtr[kCCKeySizeAES128+1];
        memset(keyPtr, 0, sizeof(keyPtr));
        [gkey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
        
        char ivPtr[kCCBlockSizeAES128+1];
        memset(ivPtr, 0, sizeof(ivPtr));
        [gIv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
        
        NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
        NSUInteger dataLength = [data length];
        
        int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
        int newSize = 0;
        
        if(diff > 0)
        {
            newSize = dataLength + diff;
        }
        
        char dataPtr[newSize];
        memcpy(dataPtr, [data bytes], [data length]);
        for(int i = 0; i < diff; i++)
        {
            dataPtr[i + dataLength] = 0x00;
        }
        
        size_t bufferSize = newSize + kCCBlockSizeAES128;
        void *buffer = malloc(bufferSize);
        memset(buffer, 0, bufferSize);
        
        size_t numBytesCrypted = 0;
        
        CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                              kCCAlgorithmAES128,
                                              0x0000,               //No padding
                                              keyPtr,
                                              kCCKeySizeAES128,
                                              ivPtr,
                                              dataPtr,
                                              sizeof(dataPtr),
                                              buffer,
                                              bufferSize,
                                              &numBytesCrypted);
        
        if (cryptStatus == kCCSuccess) {
            NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
            return [GTMBase64 stringByEncodingData:resultData];
        }
        free(buffer);
        return nil;
    }
    
    +(NSString *)AES128Decrypt:(NSString *)encryptText
    {    
        char keyPtr[kCCKeySizeAES128 + 1];
        memset(keyPtr, 0, sizeof(keyPtr));
        [gkey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
        
        char ivPtr[kCCBlockSizeAES128 + 1];
        memset(ivPtr, 0, sizeof(ivPtr));
        [gIv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
        
        NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
        NSUInteger dataLength = [data length];
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc(bufferSize);
        
        size_t numBytesCrypted = 0;
        CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                              kCCAlgorithmAES128,
                                              0x0000,
                                              keyPtr,
                                              kCCBlockSizeAES128,
                                              ivPtr,
                                              [data bytes],
                                              dataLength,
                                              buffer,
                                              bufferSize,
                                              &numBytesCrypted);
        if (cryptStatus == kCCSuccess) {
            NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
            return [[[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding] autorelease];
        }
        free(buffer);
        return nil;
    }
    
    @end
    

      以上就是最基本的AES 128 CBC Nopadding的加密算法了。如果要使用ECB或者PKCS7Padding模式那么,就需要在.m文件里简单的作出点修改,修改CCCryptorStatus的初始化,如下:

    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                              kCCAlgorithmAES128,
                                              0x0000 | kCCOptionECBMode, // 这里添加ECB模式,如果需要PKCS7Padding,那么后面再加上 | kCCOptionPKCS7Padding即可
                                              keyPtr,
                                              kCCKeySizeAES128,
                                              ivPtr,
                                              dataPtr,
                                              sizeof(dataPtr),
                                              buffer,
                                              bufferSize,
                                              &numBytesCrypted);    
    

      当然,加密解密里面都需要修改CCCryptorStatus的初始化,保持一致。

      PS:博主在使用自己修改后的AES 128 ECB Nopadding加密方法的时候,遇到一个问题,就是解密之后的字符串末尾会有一长串的''结束符,这样导致无法正确解析JSON对象,虽然经过简单处理不影响使用,但是最好还是一步到位最合适,不知有没有大神能帮助解决下这个问题。

  • 相关阅读:
    xcode command line 安装
    Android 报错:error: too many padding sections on bottom border
    一文深入浅出理解国产开源木兰许可系列协议
    SpringBoot接口 如何生成接口文档之非侵入方式(通过注释生成)SmartDoc?
    SpringBoot接口 如何优雅的对接口返回内容统一封装?
    SpringBoot数据库管理 用flyway对数据库管理和迁移
    SpringBoot接口 如何优雅的写Controller并统一异常处理?
    SpringBoot开发 什么是热部署和热加载?devtool的原理是什么?
    SpringBoot接口 如何优雅的对参数进行校验?
    SpringBoot接口 如何生成接口文档之Swagger技术栈?
  • 原文地址:https://www.cnblogs.com/leotangcn/p/4248414.html
Copyright © 2020-2023  润新知