iOS 解决 IAGAesGcm 框架崩溃问题解决

1、问题描述

今天发现对大文件进行加解密时,IAGAesGcm这个开源框架会崩溃。大概是内存溢出了,并且在github的issue,有人提及,作者说不再维护,并推荐使用苹果的新AES加密框架。但此框架只支持iOS13以上,公司要求12以上都要支持。故需要解决。

2、解决方案

网上已有成熟的解决方案,使用openssl库,且可以支持iOS 所有版本系统,且代码不需要做兼容,因为是c++的库,性能也非常好。具体见这些链接。

1、openssl iOS版库地址
https://github.com/x2on/OpenSSL-for-iPhone

2、如何生成库和导入工程
https://www.jianshu.com/p/7aa9841c4eba

3、封装AES256.GCM加解密类
参考
https://www.jianshu.com/p/aab89293378a

如下是我的封装
1.NSData+AES_GCM.h

//
//  NSData+AES_GCM.h
//  encore
//
//  Created by lishi on 2024/3/6.
//

#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN



@interface NSData (AES_GCM)

- (NSData *)aes256Gcm_DencryptWithKey:(NSData *)key_data iv:(NSData *)iv_data error:(NSError **)error;

- (NSData *)aes256Gcm_EncryptWithKey:(NSData *)key_data iv:(NSData *)iv_data error:(NSError **)error;

@end

NS_ASSUME_NONNULL_END


2.NSData+AES_GCM.m

//
//  NSData+AES_GCM.m
//  encore
//
//  Created by lishi on 2024/3/6.
//

#import "NSData+AES_GCM.h"
#import "evp.h"
#import "opensslv.h"

@implementation NSData (AES_GCM)

- (NSData *)aes256Gcm_DencryptWithKey:(NSData *)key_data iv:(NSData *)iv_data error:(NSError **)error {
    if (self.length < 16) {
        // self 需要是 加密数据+tag 的组合
        return nil;
    }
    
    // 取后16位作为tag
    NSData *tagData = [self subdataWithRange:(NSRange){self.length - 16, 16}];
    // 前面是真正加密的数据
    NSData *contentData = [self subdataWithRange:(NSRange){0, self.length - 16}];
    
    char *gcm_ct = [contentData bytes];
    char *gcm_iv = [iv_data bytes];
    char *gcm_key = [key_data bytes];
    unsigned char * ptBytes = (unsigned char * )malloc(self.length);

    int declen = 0;
    
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    
    if (!EVP_DecryptInit(ctx, EVP_aes_256_gcm(), NULL, NULL)) {
        *error = [self errorWithDescription:@"EVP_DecryptInit EVP_aes_256_gcm() failed."];
        return nil;
    }
    
    EVP_CIPHER_CTX_set_padding(ctx, 0);
    
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, [iv_data length], NULL)) {
        *error = [self errorWithDescription:@"EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_IVLEN Dencrypt failed."];
        return nil;
    }
    
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, [tagData bytes])) {
        *error = [self errorWithDescription:@"EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_TAG Dencrypt failed."];
        return nil;
    }
    
    if (!EVP_DecryptInit(ctx, NULL, gcm_key, gcm_iv)) {
        *error = [self errorWithDescription:@"EVP_DecryptInit Dencrypt set key and iv failed."];
        return nil;
    }
    
    if (!EVP_DecryptUpdate(ctx, ptBytes, &declen, gcm_ct, [contentData length])) {
        *error = [self errorWithDescription:@"EVP_DecryptUpdate Dencrypt failed."];
        return nil;
    }
    
    // 得到解密数据
    NSMutableData *ptgcmData = [NSMutableData dataWithCapacity:0];
    [ptgcmData appendBytes:ptBytes length:declen];
    
    if (!EVP_DecryptFinal(ctx,  [ptgcmData bytes] + declen, &declen)) {
        *error = [self errorWithDescription:@"EVP_DecryptFinal tag failed"];
        return nil;
    }
    
    EVP_CIPHER_CTX_free(ctx);
    
    return ptgcmData;
}

- (NSData *)aes256Gcm_EncryptWithKey:(NSData *)key_data iv:(NSData *)iv_data error:(NSError **)error {
    
    char *gcm_ct = [self bytes];
    char *gcm_iv = [iv_data bytes];
    char *gcm_key = [key_data bytes];
    unsigned char * ctBytes = (unsigned char * )malloc(self.length);

    NSMutableData *engcmData = [[NSMutableData alloc] initWithCapacity:self.length];

    unsigned char tag[16];
    int enclen = 0;
    
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    
    if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
        *error = [self errorWithDescription:@"EVP_EncryptInit_ex EVP_aes_256_gcm() failed."];
        return nil;
    }
    
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, [iv_data length], NULL)) {
        *error = [self errorWithDescription:@"EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_IVLEN Encryp failed."];
        return nil;
    }
    
    if (!EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv)) {
        *error = [self errorWithDescription:@"EVP_DecryptInit Encryp set key and iv failed."];
        return nil;
    }
    
    if (!EVP_EncryptUpdate(ctx, ctBytes, &enclen, (const unsigned char *)[self bytes], [self length])) {
        *error = [self errorWithDescription:@"EVP_DecryptUpdate Encrypt data failed."];
        return nil;
    }
    // 拼接 iv 数据
    [engcmData appendBytes:gcm_iv length:12];
    
    // 拼接加密数据
    [engcmData appendBytes:ctBytes length:enclen];
    
    if (!EVP_EncryptFinal (ctx, [engcmData bytes] + enclen, &enclen)) {
        *error = [self errorWithDescription:@"EVP_DecryptFinal Encrypt failed"];
        return nil;
    }

    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
        *error = [self errorWithDescription:@"EVP_CIPHER_CTX_ctrl get tag failed"];
        return nil;
    }
    // 拼接 tag
    [engcmData appendBytes:tag length:16];

    EVP_CIPHER_CTX_free(ctx);
    return engcmData;
}


-(NSError *)errorWithDescription:(NSString *)errorinfo{
    NSString *domain = @"com.chbank.aes_gcm";
    NSInteger code = -101;
    NSDictionary *userInfo = @{
        NSLocalizedDescriptionKey: errorinfo,
        NSLocalizedFailureReasonErrorKey: errorinfo,
        NSLocalizedRecoverySuggestionErrorKey: @"aes gcm failed,check class NSData+AES_GCM"
    };
    NSError *error = [NSError errorWithDomain:domain code:code userInfo:userInfo];
    return error;
}

@end

测试

NSString *testStr = @"今天去吃老乡鸡";
NSData *testStrData = [testStr dataUsingEncoding:NSUTF8StringEncoding];

NSData *keyData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"publickText" ofType:@"log"]];

#define IV_Lenght 12
#define TAG_Lenght 16

// 加密 注意后的数据结构为  iv(12位) + 加密数据 + tag(16位)
NSMutableData *ivData = [[NSMutableData alloc]initWithLength:IV_Lenght];
SecRandomCopyBytes(kSecRandomDefault, IV_Lenght, ivData.mutableBytes);
NSData *encrypedData = [testStrData aes256Gcm_EncryptWithKey:key iv:ivData error:error];
NSString *encrypedStr = [encrypedData base64EncodedStringWithOptions:0];
NSLog(@"加密后Str:%@",encrypedStr);

// 解密 注意解密前的数据结构为  iv(12位) + 加密数据 + tag(16位)
NSMutableData *data = [[NSMutableData alloc]initWithBase64EncodedString: encrypedStr options:0];
NSData *ivData = [data subdataWithRange:NSMakeRange(0, IV_Lenght)];
NSData *cipheredPlusTagData = [data subdataWithRange:NSMakeRange(IV_Lenght, data.length - IV_Lenght)];
NSData *decrypedData = [cipheredPlusTagData aes256Gcm_DencryptWithKey:key iv:ivData error:error];
NSString *decrypedStr  = [[NSString alloc] initWithData:decryptedData encoding:4];
NSLog(@"解密后Str:%@", decrypedStr);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容