密码学概论
原则:
- 在网络上不允许明文传输用户隐私信息;
- 在本地不允许明文保存用户隐私信息;
base64 编码
base64 编码:将二进制数据编码成只有65个字符的文本文件(字符)!
base64 编码包括的字符:0 ~9, a~z, A~Z, +/=
编码后文件数据会比原有文件大1/3左右。
原理
base64 编码:8位的二进制ASCII编码 —> 6位的base64编码
base64编码表:
0~63,64个字符,还有 = 表示空格,总共65个字符。
示例:
Man 转换为 base64 编码:TWFu
M 的 ASCII编码 十进制为 77 ,二进制为 01001101:
前6位二进制 010011 (十进制为19)在上面的base64编码表中为 T 。
因此 M ➡ T 。
空格情况
因为是把8个字节转换为6个字节进行编码,势必会产生位数不对应的问题。因此会使用 0 来补齐,用=表示全0的情况。(注意到base64 总会编码补齐为4个字符一组)
因此,单独的 M 用base64编码 ➡ TQ==
Objective-C 代码
// base64编码
- (NSString *)base64Encode:(NSString *)string {
// 1.将字符串转换为二进制
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
// 2.二进制数据进行编码
return [data base64EncodedStringWithOptions:0];
}
// base64解码
- (NSString *)base64Decode:(NSString *)string {
// 1.字符串转换为二进制
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
// 2.解码
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
哈希、对称加密、非对称加密
上世纪70年代开始 RSA — 非对称加密算法
RSA — 非对称加密算法
- 公钥加密,私钥解密;
- 私钥加密,公钥解密;
哈希(散列)函数
- MD5
- SHA1\SHA256\SHA512
- HMAC
对称加密算法
- DES
- 3DES
- RC2、RC4
- AES(高级密码标准,美国国家安全局使用、Apple 钥匙串访问使用、Lastpass 使用了256位的AES密钥),以目前现阶段计算机的运行效率,要暴力破解AES加密算法,需要上千万年。
散列函数
算法都是公开的。
- 对相同的数据加密,得到的结果是一样的。
- 对不同的数据加密,得到的结果是定长的。(比如MD5对不同的数据加密,得到32个字符)
- 加密之后的数据是没法解密的。(不可逆运算)
MD5 哈希算法
GitHub源码:jerilimov/NSHash——NSData、NSString 的分类,添加了MD5、SHA1、SHA256、SHA512 加密算法
NSString *pwd = @"123456";
pwd = [pwd MD5];
NSLog(@"MD5 = %@",pwd);
// MD5 = e10adc3949ba59abbe56e057f20f883e
像 MD5 这样的加密算法是无法反向解密的,但是对相同的数据加密,得到的结果是一样的。
于是 CMD5 利用散列函数的这种特性,将加密前的数据和加密后的数据进行映射保存,可以实现反向查询。
将刚才 123456 加密后的 MD5 输入,可以反向查询出原始数据:
MD5加盐:对数据先加盐,再进行MD5加密,可以增加结果的复杂度
/* 盐,足够长,足够复杂,足够咸*/
static NSString *slat = @"5O9Jc!9%N^6Kd*dcS9Or$&fSVWmC^xku2@Lg0xd8CL0Sl$omN6zQS7c7YrHhtwn@";
NSString *pwd = @"123456";
pwd = [[pwd stringByAppendingString:slat] MD5];
NSLog(@"MD5 = %@",pwd);
// MD5 = 04f60881265e2b240b217f8deaaa8e12
再将此MD5密码放到该网站上进行查询:
没有查到,结果显示,被反向查询出来的难度就会加大。
缺点:盐是固定的,如果盐被泄露,数据就会不安全。
注:哈希算法&加密算法的区分
- MD5、HMAC、SHA 等所有的哈希算法严格上来说并不能称之为加密算法,它只能说是密码学中的哈希算法。
- 加密算法加密之后是可以解密的,而哈希算法无法反向解出原始数据。
- 哈希算法通常用于校验数据的完整性,例如:校验下载后的安装包文件是否被篡改、删减或植入恶意代码。
HMAC 哈希算法
//-----------------------------------------------------
#import <Foundation/Foundation.h>
@interface NSString (Hash)
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
@end
#import "NSString+Hash.h"
#import <CommonCrypto/CommonHMAC.h>
@implementation NSString (Hash)
- (NSString *)hmacMD5StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgMD5 withKey:key];
}
- (NSString *)hmacSHA1StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgSHA1 withKey:key];
}
- (NSString *)hmacSHA256StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgSHA256 withKey:key];
}
- (NSString *)hmacSHA512StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgSHA512 withKey:key];
}
#pragma mark - Helpers
- (NSString *)hmacStringUsingAlg:(CCHmacAlgorithm)alg withKey:(NSString *)key
{
size_t size;
switch (alg) {
case kCCHmacAlgMD5:
size = CC_MD5_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA1:
size = CC_SHA1_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA224:
size = CC_SHA224_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA256:
size = CC_SHA256_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA384:
size = CC_SHA384_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA512:
size = CC_SHA512_DIGEST_LENGTH;
break;
default:
return nil;
}
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *messageData = [self dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *mutableData = [NSMutableData dataWithLength:size];
CCHmac(alg, keyData.bytes, keyData.length, messageData.bytes, messageData.length, mutableData.mutableBytes);
return [self stringFromBytes:(unsigned char *)mutableData.bytes length:(int)mutableData.length];
}
- (NSString *)stringFromBytes:(unsigned char *)bytes length:(int)length
{
NSMutableString *mutableString = @"".mutableCopy;
for (int i = 0; i < length; i++)
[mutableString appendFormat:@"%02x", bytes[i]];
return [NSString stringWithString:mutableString];
}
@end
测试
// HMAC 用一个密钥加密,并且做了两次散列。
// 在实际的开发中,密钥来自于服务器。——对应一个帐号,一个KEY
NSString *pwd = @"123456";
pwd = [pwd hmacMD5StringWithKey:@"Key"];
NSLog(@"MD5 = %@",pwd);
// MD5 = a7cac7471d2c9eb7a944e07d44d305ca
将此MD5密码放到该网站上查询也是查不到的。
项目实际使用流程:
- 服务器根据用户帐号生成KEY,发送给客户端;
- 客户端获得KEY并保存到本地,使用KEY对数据进行HMAC加密,将加密后的数据发送给服务器;
- 服务器对加密后对数据进行验证。
客户端登录时,没有KEY就先根据帐号从服务器获取KEY保存到本地,再将获得的KEY对密码进行加密。
防止KEY泄露,对KEY进行非对称加密、定期更换KEY。
QQ设备锁:
- 本地有KEY——为授权手机。
- 本地没有KEY,未授权设备,需要允许服务器发送KEY。允许一次登录,本地不保存KEY,允许多次登录,保存KEY到本地。
- 短信验证码登录获取KEY。
- 申诉获取KEY。
HMAC加密+时间戳(不加秒)
之前:
验证方式:HMAC密码直接匹配是否正确。
现在:
客户端:(HMAC密码+“201711010358”).MD5校验
服务器:
- (HMAC密码+“201711010359”).MD5校验
- (HMAC密码+“201711010358”).MD5校验
密码验证有效期最长2分钟,超过2分钟,验证失败。
有经验的服务器人员,会在返回数据时,返回时间戳。
登录等待时间,不要超过6秒!!!提示用户:你的网络不稳定,请稍后再试!
终端测试命令:
md5 -s "string" #这是 Apple 用的 openssl 标准进行的MD5加密
MD5使用场景,百度搜索引擎(拆词搜索思路)运用 以及百度云盘文件识别运用
搜索引擎的拆词搜索 && 词库
无论搜索 Apple Blue Sky
,还是搜索Sky Blue Apple
,得到的返回结果是一样的。
原理
先计算各个单词的MD5
- MD5 ("Apple") = 9f6290f4436e5a2351f12e03b6433c3c
- MD5 ("Blue") = 9594eec95be70e7b1710f730fdda33d9
- MD5 ("Sky") = 03462a41aec357b74c89eb8d272532f7
然后再对MD5值进行按位相加,得到的结果是一样的。
再去搜索匹配结果的数据。
散列碰撞:两个不同的数据,哈希之后,得到相同的哈希值!
从理论的角度出发,有无限个碰撞可能!
MD5 32为字符,它能表达的数据个数是有限的,而被加密的数据是无限个。
其他使用场景
通过数据的散列值,判断数据是否相等,保存云盘数据(相同的数据在云上保存一份)。
正版软件使用哈希进行文件识别。
对下载后的软件安装版进行 MD5 校验,判断安装包是否被污染。