DEMO 綜述:
一行代碼完成AES加密季惯,加密模式 AES128 + ECB + NoPadding
DEMO下載地址:github.com/IMCCP/CCPAESEncode
DEMO GIF
DEMO 簡(jiǎn)介:
最近項(xiàng)目中用到AES加密吠各,在這里整理成篇,供大家參考閱讀勉抓,在使用該demo過程中贾漏,你可能會(huì)遇到一些問題,首先你需要看一下下面的demo簡(jiǎn)介藕筋,看看該demo 是否適合你的項(xiàng)目纵散。
項(xiàng)目中的AES加解密主要用在網(wǎng)絡(luò)請(qǐng)求過程中對(duì)上傳的參數(shù)進(jìn)行加密,對(duì)從后臺(tái)服務(wù)器獲取的數(shù)據(jù)進(jìn)行解密。
整體的加密流程為:
加密的過程: 參數(shù)字典 --> json字符串 --> base64加密后的字符串 --> AES加密后base64再加密 --> 輸出最終加密后的字符串;
解密的過程:
后臺(tái)服務(wù)器獲取加密的字符串 -->base64解密 --> AES解密后base64解密 --> json字符串 --> 數(shù)據(jù)字典;(與加密的過程相反)
網(wǎng)上對(duì)AES的詳細(xì)介紹已經(jīng)有很多伍掀,在這里不做贅述掰茶,如果你需要了解這些知識(shí),度娘蜜笤,google 去吧.
在這里感謝這些 blog 的作者,讓我在開發(fā)過程中少走了很多彎路:
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/?(如何防止客戶端被破解)
我們公司后臺(tái)為PHP,移動(dòng)端有iOS與Android, 討論后選擇AES的加密模式為 AES128 + ECB + NoPadding (注意是否滿足你的加密需求)濒蒋。
為什么選擇這種加密模式:
因?yàn)锳ES的加密規(guī)則 --> 原輸入數(shù)據(jù)不夠16字節(jié)的整數(shù)位時(shí),就要補(bǔ)齊把兔。因此就會(huì)有padding(填充模式)沪伙,若使用不同的padding,那么加密
出來的結(jié)果也會(huì)不一樣县好。
如果采用PKCS7Padding或者PKCS5Padding這種加密方式围橡,末端添加的數(shù)據(jù)可能不固定,在解碼后需要把末端多余的字符去掉缕贡,比較棘手翁授。
如果不管補(bǔ)齊多少位,末端都是'\0',去掉的話比較容易操作晾咪。 最主要的是能使得
iOS/Android/PHP相互通信收擦,也是加密過程中最難搞的地方,尤其需要開發(fā)者注意禀酱。
(注意:別的加密模式也可以完成三者之間的通信炬守,只是查找方法的時(shí)候 AES128 + ECB + NoPadding
這種加密方式使用的比較多,希望能有更好用的加密方式)
項(xiàng)目中用到了 google 的 base64 加解密庫 GTMBase64剂跟,但是這個(gè)庫已經(jīng)有很多年沒有更新 還是 MRC 開發(fā)模式,需要手動(dòng)配置一下:
1.選擇項(xiàng)目中的Targets酣藻,選中你所要操作的Target曹洽,
2.選Build Phases,在其中Complie Sources中選擇需要ARC的文件雙擊辽剧,并在輸入框中輸入 -fno-objc-arc
DEMO 中工具類的介紹:
.h文件
/************************************************************************
函數(shù)名稱 : + (NSString *)inputDictionary:(NSMutableDictionary *)dict andSecretKey:(NSString *)key;
函數(shù)描述 : 將傳進(jìn)來的字典 進(jìn)行 AES 加密后轉(zhuǎn)成json字符串
加密的過程: 字典 --> json字符串 --> base64加密后的字符串 --> AES加密后base64再加密 --> 輸出加密后的字符串
輸入?yún)?shù) : base64String? base64編碼的字符串 ; key? 密鑰
返回參數(shù) :? (NSDictionary *)dic? 字典
**********************************************************************
*/
+ (NSString *)inputDictionary:(NSMutableDictionary *)dict andSecretKey:(NSString *)key;
/************************************************************************
函數(shù)名稱 : + (NSDictionary *)inputBase64String:(NSString *)base64String andSecretKey:(NSString *)key;
函數(shù)描述 : 將傳進(jìn)來的base64編碼的字符 進(jìn)行 AES 解密后轉(zhuǎn)成字典
解密的過程 : 與加密過程相反
輸入?yún)?shù) : base64String? base64編碼的字符串 ; key? 密鑰
返回參數(shù) :? (NSDictionary *)dic? 字典
**********************************************************************
*/
+ (NSDictionary *)inputBase64String:(NSString *)base64String andSecretKey:(NSString *)key;
/************************************************************************
函數(shù)名稱 : + (NSString*)dictionaryToJson:(NSDictionary *)dic;
函數(shù)描述 : 將字典轉(zhuǎn)換成字符串
輸入?yún)?shù) : (NSDictionary *)dic? 字典
返回參數(shù) : 字符串
**********************************************************************
*/
+ (NSString*)dictionaryToJson:(NSDictionary *)dic;
/************************************************************************
函數(shù)名稱 : + (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString;
函數(shù)描述 : 將json字符串轉(zhuǎn)換成字典
輸入?yún)?shù) : (NSString *)jsonString? Json格式的字符串
返回參數(shù) : 字典
**********************************************************************
*/
+ (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,//這個(gè)參數(shù)iv是個(gè)固定值偷崩,通常直接使用密鑰即可。大家一定要注視這個(gè)參數(shù)撞羽,如果安卓阐斜、服務(wù)端和iOS端不統(tǒng)一,那么加密結(jié)果就會(huì)不一樣诀紊,解密可能能解出來谒出,但是解密后在末尾會(huì)出現(xiàn)一些\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,//這個(gè)參數(shù)iv是個(gè)固定值杀狡,通常直接使用密鑰即可蒙畴。大家一定要注視這個(gè)參數(shù),如果安卓呜象、服務(wù)端和iOS端不統(tǒng)一忍抽,那么加密結(jié)果就會(huì)不一樣,解密可能能解出來董朝,但是解密后在末尾會(huì)出現(xiàn)一些\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 {
//上面加密的結(jié)果 NSString *AESString = @"yNgE5k1LAo7jfWk4oLqQv5YHxhBSOG0g6SjdFJoatZ2oTDL+jv1TpL7KWVcbMTH85kQCEFX9KWbsgegrwZ3JgrQ99I70Fd
LKjSieKe7rfTz1qmbL9gBoe8GJz3TeqmIs7252agKLSDofW8J3mK8y1F4Y3tdnMGsWO9DZLhS/1v0=";
//解密
NSDictionary *dict = [CCPAESTool inputBase64String:AESString andSecretKey:secrectKey];
NSString *jsonString = [CCPAESTool dictionaryToJson:dict];
self.showLabel.text = jsonString;
}
項(xiàng)目中遇到的一些坑祟绊,在 DEMO 中都已經(jīng)注釋出來,寫的比較清楚哥捕,如果該 DEMO 幫助了您牧抽,也希望能
給個(gè) star鼓勵(lì)一下,如果在使用中您有任何問題遥赚,可以在 github issues,我會(huì)盡自己能力給您答復(fù) 扬舒。