AES加密,iOS、android、PHP 相互兼容

DEMO 综述:

一行代码完成AES加密,加密模式 AES128 + ECB + NoPadding

DEMO下载地址:github.com/IMCCP/CCPAESEncode

DEMO GIF


DEMO 简介:

最近项目中用到AES加密,在这里整理成篇,供大家参考阅读,在使用该demo过程中,你可能会遇到一些问题,首先你需要看一下下面的demo简介,看看该demo 是否适合你的项目。

项目中的AES加解密主要用在网络请求过程中对上传的参数进行加密,对从后台服务器获取的数据进行解密。

整体的加密流程为:

加密的过程: 参数字典 --> json字符串 --> base64加密后的字符串 --> AES加密后base64再加密 --> 输出最终加密后的字符串;

解密的过程:

后台服务器获取加密的字符串 -->base64解密 --> AES解密后base64解密 --> json字符串 --> 数据字典;(与加密的过程相反)

网上对AES的详细介绍已经有很多,在这里不做赘述,如果你需要了解这些知识,度娘,google 去吧.

在这里感谢这些 blog 的作者,让我在开发过程中少走了很多弯路:

http://www.open-open.com/lib/view/open1453530956573.html

http://blog.csdn.net/huangwenkui1990/article/details/48292865

http://blog.csdn.net/j_akill/article/details/44079597

https://wordpress-xiaominfc.rhcloud.com/?p=22#comment-12

http://www.360doc.com/content/15/1012/10/20918780_505049436.shtml

tanqisen.github.io/blog/2014/06/06/how-to-prevent-app-crack/ (如何防止客户端被破解)

我们公司后台为PHP,移动端有iOS与Android, 讨论后选择AES的加密模式为 AES128 + ECB + NoPadding (注意是否满足你的加密需求)。

为什么选择这种加密模式:

因为AES的加密规则 --> 原输入数据不够16字节的整数位时,就要补齐。因此就会有padding(填充模式),若使用不同的padding,那么加密

出来的结果也会不一样。

如果采用PKCS7Padding或者PKCS5Padding这种加密方式,末端添加的数据可能不固定,在解码后需要把末端多余的字符去掉,比较棘手。

如果不管补齐多少位,末端都是'\0',去掉的话比较容易操作。 最主要的是能使得

iOS/Android/PHP相互通信,也是加密过程中最难搞的地方,尤其需要开发者注意。

(注意:别的加密模式也可以完成三者之间的通信,只是查找方法的时候 AES128 + ECB + NoPadding

这种加密方式使用的比较多,希望能有更好用的加密方式)

项目中用到了 google 的 base64 加解密库 GTMBase64,但是这个库已经有很多年没有更新 还是 MRC 开发模式,需要手动配置一下:

1.选择项目中的Targets,选中你所要操作的Target,

2.选Build Phases,在其中Complie Sources中选择需要ARC的文件双击,并在输入框中输入 -fno-objc-arc

DEMO 中工具类的介绍:

.h文件

/************************************************************************

函数名称 : + (NSString *)inputDictionary:(NSMutableDictionary *)dict andSecretKey:(NSString *)key;

函数描述 : 将传进来的字典 进行 AES 加密后转成json字符串

加密的过程: 字典 --> json字符串 --> base64加密后的字符串 --> AES加密后base64再加密 --> 输出加密后的字符串

输入参数 : base64String  base64编码的字符串 ; key  密钥

返回参数 :  (NSDictionary *)dic  字典

**********************************************************************

*/

+ (NSString *)inputDictionary:(NSMutableDictionary *)dict andSecretKey:(NSString *)key;

/************************************************************************

函数名称 : + (NSDictionary *)inputBase64String:(NSString *)base64String andSecretKey:(NSString *)key;

函数描述 : 将传进来的base64编码的字符 进行 AES 解密后转成字典

解密的过程 : 与加密过程相反

输入参数 : base64String  base64编码的字符串 ; key  密钥

返回参数 :  (NSDictionary *)dic  字典

**********************************************************************

*/

+ (NSDictionary *)inputBase64String:(NSString *)base64String andSecretKey:(NSString *)key;

/************************************************************************

函数名称 : + (NSString*)dictionaryToJson:(NSDictionary *)dic;

函数描述 : 将字典转换成字符串

输入参数 : (NSDictionary *)dic  字典

返回参数 : 字符串

**********************************************************************

*/

+ (NSString*)dictionaryToJson:(NSDictionary *)dic;

/************************************************************************

函数名称 : + (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString;

函数描述 : 将json字符串转换成字典

输入参数 : (NSString *)jsonString  Json格式的字符串

返回参数 : 字典

**********************************************************************

*/

+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString;


.m文件

+ (NSString *)inputDictionary:(NSMutableDictionary *)dict andSecretKey:(NSString *)key{

NSString *jsonString = [CCPAESTool dictionaryToJson:dict];

NSString *jsonBase64Str = [GTMBase64 encodeBase64String:jsonString];

NSString *encryptStr = [CCPAESTool AES128Encrypt:jsonBase64Str andSecretKey:key];

return encryptStr;

}

+ (NSDictionary *)inputBase64String:(NSString *)base64String andSecretKey:(NSString *)key {

NSString * jsonString = [CCPAESTool AES128Decrypt:base64String andSecretKey:key];

NSDictionary *dict = [CCPAESTool dictionaryWithJsonString:jsonString];

return dict;

}

/**

*  AES 加密 解密

*/

+(NSString *)AES128Encrypt:(NSString *)plainText andSecretKey:(NSString *)secretKeys

{

char keyPtr[kCCKeySizeAES128+1];

memset(keyPtr, 0, sizeof(keyPtr));

[secretKeys getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];

NSUInteger dataLength = [data length];

NSUInteger diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);

NSUInteger 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] = 0x0000; ////No padding

}

size_t bufferSize = newSize + kCCBlockSizeAES128;

void *buffer = malloc(bufferSize);

memset(buffer, 0, bufferSize);

size_t numBytesCrypted = 0;

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,

kCCAlgorithmAES128,

kCCOptionECBMode,  //使用的是 kCCOptionECBMode ,也就是ECB。在安卓端和PHP端,也得使用ECB

keyPtr,

kCCKeySizeAES128,

NULL,//这个参数iv是个固定值,通常直接使用密钥即可。大家一定要注视这个参数,如果安卓、服务端和iOS端不统一,那么加密结果就会不一样,解密可能能解出来,但是解密后在末尾会出现一些\0、\t之类的。(注: 这里使用NULL)

dataPtr,

sizeof(dataPtr),

buffer,

bufferSize,

&numBytesCrypted);

if (cryptStatus == kCCSuccess) {

NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];

return [GTMBase64 encodeBase64Data:resultData];

}

free(buffer);

return nil;

}


+ (NSString *)AES128Decrypt:(NSString *)encryptText andSecretKey:(NSString *)secretKeys

{

char keyPtr[kCCKeySizeAES128 + 1];

memset(keyPtr, 0, sizeof(keyPtr));

[secretKeys getCString:keyPtr maxLength:sizeof(keyPtr) 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,

kCCOptionECBMode,//使用的是 kCCOptionECBMode ,也就是ECB。在安卓端和PHP端,也得使用ECB

keyPtr,

kCCBlockSizeAES128,

NULL,//这个参数iv是个固定值,通常直接使用密钥即可。大家一定要注视这个参数,如果安卓、服务端和iOS端不统一,那么加密结果就会不一样,解密可能能解出来,但是解密后在末尾会出现一些\0、\t之类的。(注:这里使用NULL)

[data bytes],

dataLength,

buffer,

bufferSize,

&numBytesCrypted);

if (cryptStatus == kCCSuccess) {

NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];

return [GTMBase64 decodeBase64Data:resultData];

}

free(buffer);

return nil;

}


+ (NSString*)dictionaryToJson:(NSMutableDictionary *)dic {

NSError *parseError = nil;

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];

return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

}

+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {

if (jsonString == nil) {

return nil;

}

NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];

NSError *err;

NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];

if(err) {

NSLog(@"json解析失败:%@",err);

return nil;

}

return dic;

}


DEMO 使用示例

//加密

-(IBAction)clickEncodeBtn:(UIButton *)sender {

NSMutableDictionary *dict = [NSMutableDictionary dictionary];

dict[@"HELLO"] = @"WORLD";

dict[@"GIT"] = @"HUB";

dict[@"https"] = @"github.com/IMCCP";

NSString *AESString = [CCPAESTool inputDictionary:self.dict andSecretKey:secrectKey];

self.showLabel.text = AESString;

}

//解密

-(IBAction)clickDecodeBtn:(UIButton *)sender {

//上面加密的结果 NSString *AESString = @"yNgE5k1LAo7jfWk4oLqQv5YHxhBSOG0g6SjdFJoatZ2oTDL+jv1TpL7KWVcbMTH85kQCEFX9KWbsgegrwZ3JgrQ99I70Fd

LKjSieKe7rfTz1qmbL9gBoe8GJz3TeqmIs7252agKLSDofW8J3mK8y1F4Y3tdnMGsWO9DZLhS/1v0=";

//解密

NSDictionary *dict = [CCPAESTool inputBase64String:AESString andSecretKey:secrectKey];

NSString *jsonString = [CCPAESTool dictionaryToJson:dict];

self.showLabel.text = jsonString;

}

项目中遇到的一些坑,在 DEMO 中都已经注释出来,写的比较清楚,如果该 DEMO 帮助了您,也希望能

给个 star鼓励一下,如果在使用中您有任何问题,可以在 github issues,我会尽自己能力给您答复 。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • /**ios常见的几种加密方法: 普通的加密方法是讲密码进行加密后保存到用户偏好设置( [NSUserDefaul...
    彬至睢阳阅读 2,906评论 0 7
  • 常见的加密算法 MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ RSA \ IDEA \ D...
    小小啄阅读 3,086评论 0 9
  • 前言: 在我们开发中免不了和服务器做一些数据交互,在交互过程中走得都是http请求,这类请求不像https那样的安...
    退役程序猿阅读 4,564评论 2 6
  • 首先罗列一些知识点: 1.加密算法通常分为对称性加密算法和非对称性加密算法:对于对称性加密算法,信息接收双方都需事...
    JonesCxy阅读 1,366评论 2 4
  • 楚楚: 不知你有没有看过那部韩国电影,名字叫《密爱》,讲的是一对已婚男女出轨的事。剧中的女主人公因为丈夫的情人找上...
    烟花_阅读 546评论 27 19