概要:这一篇博客主要说明下iOS客户端动态部署方案中,patch(补丁)是如何比较安全的加载到客户端中。
在整个过程中,需要使用RSA来加密(你可以选择其它的非对称加密算法),MD5来做校验(同样,你也可以选择其他的算法)。
iOS客户端中RSA加解密的例子不是很多,我在网络上寻找了一些开源代码,发现揭秘算法有误。我就在其基础上做了修改,修复了问题。并且我重新整理了一份,并且支持cocoapod接入,下面是github地址。以后我还会详细的说明RSA加密的原理,以及github上代码实现。
https://github.com/qianhongqiang/RSAEncryptor
生成RSA公私钥文件
RSA公私钥声称可以参考下面的文章,照着一步步做就是了。其中,公私钥长度建议1024位以上,我自己则采用了2048位的。
http://blog.csdn.net/yi_zz32/article/details/50097325
使用.der后缀的公钥和.p12为后缀的私钥作为秘钥对,对尚未加密的patcher进行加密。
MD5校验
因为网络传输存在不稳定性,倘若传输中某个字节出现了错误,那么加载patch后肯定会运行失败,在这种情况下,我们是不能加载patcher的。游戏游戏在下载patch后,都会提示正在进行MD5校验(或其他算法校验),都是这个道理。MD5的功能只是单纯的进行校验。我直接把使用的代码贴出来了,比较短。需要倒入库#import <CommonCrypto/CommonDigest.h>,你可以直接拷贝。
+(NSString*)fileMD5:(NSString*)path
{
NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
if( handle== nil ) return @"ERROR GETTING FILE MD5"; // file didnt exist
CC_MD5_CTX md5;
CC_MD5_Init(&md5);
BOOL done = NO;
while(!done)
{
NSData* fileData = [handle readDataOfLength: 256 ];
CC_MD5_Update(&md5, [fileData bytes], (uint32_t)[fileData length]);
if( [fileData length] == 0 ) done = YES;
}
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(digest, &md5);
NSString* s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1],
digest[2], digest[3],
digest[4], digest[5],
digest[6], digest[7],
digest[8], digest[9],
digest[10], digest[11],
digest[12], digest[13],
digest[14], digest[15]];
return s;
}
生成加密后的Patcher
目前来说,我紧紧打算用patche做bug紧急修复的用途,没有打算直接使用它发布新功能,所以patcher中紧紧包涵脚本的文本,不包含图片等文件。
自己定义了流的生成与解析过程:
写入md5值的长度,我这里用1个字节表示,已经足够的长度来表示了。
NSMutableData *finalData = [NSMutableData data];//所有的data最后都写入这个data中
NSString *fileMD5 = [MD5 fileMD5:dataFileName];
NSData *md5Data = [fileMD5 dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger length = [md5Data length];
unsigned char bit8 = length & 0x000000FF;//提取低八位
[finalData appendBytes:&bit8 length:1];
[finalData appendData:md5Data];
最后在把RSA加密后的data拼接到finalData中,在把data输出到文件。这样patcher就搞定了。
解密patcher
patcher下载客户端后,就需要对patcher进行解析。解析就逆着patcher的生成过程就可以
NSData *decryptFileData = [NSData dataWithContentsOfFile:encryptFileName]; //获取文件的data
//读取文件的第一个字节,
int8_t v1;
[decryptFileData getBytes:&v1 range:NSMakeRange(0,1)];
//查看MD5值的长度
int getMG5Length = (int32_t)v1 & 0x0ff;
//查看md5信息
NSData *getmd5Data = [decryptFileData subdataWithRange:NSMakeRange(1, getMG5Length)];
NSString *fileMD5s = [[NSString alloc] initWithData:getmd5Data encoding:NSUTF8StringEncoding];
//获取真正的patcher文本的data
NSData *contentData = [decryptFileData subdataWithRange:NSMakeRange(1+getMG5Length, decryptFileData.length - 1 -getMG5Length)];
该有的信息全部存在了,只需要将data转成文本,再次md5跟校验值比较,是否一致,一致的话,那么这个patcher就是正常的,可以加载。如果不正常的话,那么根据app需求,可以重新下载等等处理。