iOS加密(一):Base64 +AES +MD5模式

由于公司对于信息安全比较注重,需要对json数据并用AES加密,然后生成url_safe base64编码。然后继续拼接时间戳 session还有其他字段进行MD5加密。然后使用RAC签名后传输。本来没觉得什么,以为加密算法之前也接触过,或者去网上直接套用就好,结果,发现没那么简单 = =

一: Base64

  • 是网络上使用最广泛的编码系统,能够将任何二进制数据,转换成只有 65 个字符 * 组成的文本文件.
  • 编码后的数据由 a-z A-Z 0-9 + / = 表示.
  • base64 编码后的结果能够反算,不够安全.
  • base64 是所有现代加密算法的基础算法.

base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本,使用时,在传输编码方式中指定base64。使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。

完整的base64定义可见RFC 1421和RFC 2045。编码后的数据比原始数据略长,为原来的4/3.。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。( 如果源码为760个字符, 则编码后的长度为760 * (4 / 3) + 10(换行符) )

对Man进行编码
ABC编码

URL_Safe Base64 这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符,因为标准base64包含"+"和"/",因此不适合直接放在URL中传输.因为URL编译器会将"+","/"转换成XX%的样式.而这些"%"在录入数据库的时候还会进行转码,为了解决此问题可采用一种适用于URL的改进base64,它不在末位添加"=",将"+"转换成"-",将"/"转换成"_".

iOS原生API的有它自己的局限性, 所以我使用了base64的神器(GTMBase, 这个框架满足了每一种的base64模式的编解码.)
因此为了两个平台的兼容,使用总结如下

GTMBase64 Padded YES != Java DEFAULT
GTMBase64 Padded NO == Java NO_PADDING | NO_WRAP
GTMBase64 Padded YES == Java NO_WRAP
GTMBase64 websafe Padded NO == java NO_PADDING | NO_WRAP | URL_SAFE
GTMBase64 websafe Padded YES == java NO_WRAP | URL_SAFE
GTMBase64对应的URL_Safe Base64

GTMBase64传送门

二:AES加解密

  • 相较于DES和3DES算法而言,AES算法有着更高的速度和资源使用效率,安全级别也较之更高了,被称为下一代加密标准。
  • AES使用的是对称加密.所谓对称加密就是加解密双方使用的密钥相同.因此通过一种保密的方法让客户端与服务器拥有该密钥,即可成功使用加解密.

常见的IOS中AES加密

//加密
+(NSData *) AES128EncryptWithKey:(NSData*)key data:(NSData*)data
{
    return [self doCipher:data iv:nil key:key context:kCCEncrypt error:nil];
}

//解密
+(NSData *) AES128DecryptWithKey:(NSData*)key data:(NSData*)data
{
    return [self doCipher:data iv:nil key:key context:kCCDecrypt error:nil];
}


+ (NSData *)doCipher:(NSData *)dataIn
                  iv:(NSData *)iv
                 key:(NSData *)symmetricKey
             context:(CCOperation)encryptOrDecrypt
               error:(NSError **)error
{
    CCCryptorStatus ccStatus   = kCCSuccess;
    size_t          cryptBytes = 0;
    NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
    
    ccStatus = CCCrypt( encryptOrDecrypt,
                       kCCAlgorithmAES,
                       kCCOptionECBMode | kCCOptionPKCS7Padding,
                       symmetricKey.bytes,
                       symmetricKey.length,
                       iv.bytes,
                       dataIn.bytes,
                       dataIn.length,
                       dataOut.mutableBytes,
                       dataOut.length,
                       &cryptBytes);
    
    if (ccStatus == kCCSuccess) {
        dataOut.length = cryptBytes;
    }
    else {
        if (error) {
            *error = [NSError errorWithDomain:@"kEncryptionError"
                                         code:ccStatus
                                     userInfo:nil];
        }
        dataOut = nil;
    }
    
    return dataOut;
}

坑爹的地方地方来了,传给后台永远是乱码.用了网上大多数方法都不行...一开始怀疑是不是URL_Safe Base64错了,或者是哪个地方没有UTF-8。与后台的沟通,反复验证数据加密后的字符串,就是对不上~~~

  • 网上拼命查资料发现好像是iv不对,iv是什么??......
iOS原生API
  • 大概意思说,此属性可选,但只能用于CBC模式。如果出现那么他的长度必须和算法的block size保持一致。 如果是因为默认选择的CBC模式而且向量没有定义,那么向量会被定义为NULL。如果选择了ECB模式或是其他的流密码算法,之前所说的逻辑都不成立。

CBC??ECB一脸懵逼,继续查资料

  • 初始化向量与密钥相比有不同的安全性需求,因此IV通常无须保密,然而在大多数情况中,不应当在使用同一密钥的情况下两次使用同一个IV。对于CBC和CFB,重用IV会导致泄露明文首个块的某些信息,亦包括两个不同消息中相同的前缀。对于OFB和CTR而言,重用IV会导致完全失去安全性。另外,在CBC模式中,IV在加密时必须是无法预测的;特别的,在许多实现中使用的产生IV的方法,例如SSL2.0使用的,即采用上一个消息的最后一块密文作为下一个消息的IV,是不安全的。
ECB模式不需要初始化向量,CBC需要。
CCCrypt重要参数

完善之后AES的代码

//AES加密
+ (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)iv withNSData:(NSData *)data
{
    char keyPtr[kCCKeySizeAES128+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    char ivPtr[kCCKeySizeAES128+1];
    bzero(ivPtr, sizeof(ivPtr));
    [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [data length];
    int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
    int newSize = 0;
    if(diff > 0)
    {
        newSize = (int)(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);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES128,
                                          0x00, //No padding
                                          keyPtr,
                                          kCCKeySizeAES128,
                                          ivPtr,
                                          dataPtr,
                                          sizeof(dataPtr),
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if(cryptStatus == kCCSuccess)
    {
        //        NSData *data =[NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        //        NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    return nil;
}
//AES解密
+ (NSData *)AES128DecryptWithKey:(NSString *)key iv:(NSString *)iv withNSData:(NSData *)data
{
    char keyPtr[kCCKeySizeAES128+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    char ivPtr[kCCKeySizeAES128+1];
    bzero(ivPtr, sizeof(ivPtr));
    [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES128,
                                          0x00, //No padding
                                          keyPtr,
                                          kCCKeySizeAES128,
                                          ivPtr,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if(cryptStatus == kCCSuccess)
    {
        //        NSData *data =[NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        // NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    return nil;
}

写个工具类复制过去就可以了

三:MD5

  • 对任意的数据进行计算,生成固定长度的字符串.32个字符.
  • 一般用来加密密码.
  • 有时候也用来验证文件下载时,是否被篡改过.
    文件下载完成之后计算文件的md5值,与服务器计算的MD5值比较,如果不一样那么这个文件在下载的过程中被篡改了.

MD5终端命令

# 得到文件的MD5值
$ md5 文件名

# 得到字符串的MD5值
md5 -s "string"
+(NSString *) md5: (NSString *) inPutText
{
    const char *cStr = [inPutText UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, strlen(cStr), result);
    
    return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
             result[0], result[1], result[2], result[3],
             result[4], result[5], result[6], result[7],
             result[8], result[9], result[10], result[11],
             result[12], result[13], result[14], result[15]
             ] lowercaseString];
}
  • 如果原始密码过于简单,直接进行MD5加密是很容易被暴力破解的.
  • 为了增强密码的安全性,防止加密的密码被暴力破解,可以向原始密码中加盐.
  • 盐 : 服务器端和客户端约定的一个字符串.
  • MD5+盐 : 原始密码+盐拼接出新的密码字符串,再进行MD加密.
  • 以上为加一勺盐,比单纯的直接MD5加密安全性要高.
  • 盐要足够的咸,越咸越安全.

RSA部分会在第二部分,如果有时间的话 笑~
参考文章:加密解密介绍

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容