iOS逆向-Hash浅谈+对称加密(II)
Hash概念
Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
Hash的特点
- 算法是公开的
- 对相同数据运算,得到的结果是一样的
- 对不用数据运算,如MD5得到的结果都是32个字符长度的字符串
- 很难找到逆向规律
Hash的运用场景
1. 登陆密码加密
- 直接使用Hash
//密码
NSString * pwd = @"123456";
//MD5 直接加密 e10adc3949ba59abbe56e057f20f883e
//不足:不够安全了。可以反查询!
pwd = pwd.md5String;
//NSString分类方法
- (NSString *)md5String {
const char *str = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), buffer);
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[strM appendFormat:@"%02x", buffer[I]];
}
return strM;
}
客户端
直接将用户输入的密码进行Hash
运算,得到结果发送给服务器验证.因为Hash
算法无法逆运算,所以就算Hash
值泄露,用户真实密码也不会泄露.
服务端
需要服务器配合,在用户注册的时候,服务端的数据库中保存的就是用户密码的Hash
值,而不是密码本身(根据Hash
的特点,对相同的数据加密结果是一样的).这样就算服务器被攻克,用户的隐私信息也能起到一定的保护.
也就是现在为什么各类产品只提供重置密码的功能,而不再有找回密码的功能了.因为服务端本身也不知道用户的真实密码.
- 加盐
//足够复杂!
static NSString * salt = @"(*(*(DS*YFHIUYF(*&DSFHUS(*AD&";
//MD5 加盐
//弊端: 盐是固定的,写死在程序里面,一旦泄露就不安全了!
pwd = [pwd stringByAppendingString:salt].md5String;
- HMAC(Hash-based Message Authentication Code)
/** HMAC
* 使用一个密钥加密,并且做两次散列!
* 在实际开发中,密钥(KEY)来自于服务器(动态的)!
* 一个账号,对应一个KEY,而且还可以跟新!
*/
pwd = [pwd hmacMD5StringWithKey:@"key"];
//NSString分类
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[strM appendFormat:@"%02x", buffer[I]];
}
return strM;
}
-
补充
如果黑客只想要拿到用户的登录权限,也就是说只需要拿到你的Hash值,就可以模拟你客户端进行登录了。
防范措施
注册的过程还是一样.服务器保存的还是一串HMAC
加密之后的HASH
值,进行校验,但是登录时的验证做点修改.
客户端
通过服务器的KEY
进行HMAC
加密,得到HMAC
的Hash串
将得到的Hash
串拼接一个时间字符串@"201807102248"
注意只到分(当然根据你的情况可以到秒)
然后将这个拼接完成的串,再次Hash
,将这个结果发给服务器验证.
服务端
服务器保存了hmac
的Hash
串,以同样的算法,拼接服务器的时间,进行运算,然后校验.比如时间是59
秒99
发送的请求.服务器正好跳过一个分钟.过程如下:
(服务器的Hash
串+@"201807102249"
)Hash
.这次不通过再来一次
(服务器的Hash
串+@"201807102248"
)Hash
.和上一分钟对比,一次通过算成功
这样的好处,可以做到每登录发送给服务器的Hash值是不一样的.黑客不能通过保存Hash值模拟登录.
2. 版权&文件识别
当然Hash
的作用除了用于登录密码加密以外.还有版权的运用.
比如如何识别一段视频或者一段音频,这种数字文件是正版的.这个时候,我们使用肉眼是没法判断的.因为翻录的视频和音频文件几乎看不出来.但是,文件的二进制不一样,它的Hash
值是不会欺骗群众的.所以类似YouTube
这样的网站,在你上传视频的时候,它会将文件的Hash
值保存.当其他的网站上传这个视频,那么看是否是正版,就是对比文件的Hash值.
既然可以识别文件.那么还有一个非常广泛运用的就是像百度云这样的云端服务.
举个例子:
很多小伙伴保留的视频,经常被"和谐".有的人将视频的名称全部改为葫芦兄弟,黑猫警长但是还是被和谐了.
百度识别你的视频文件,和你的文件名称,以及文件后缀(有人改成.txt)没有半毛钱关系.它只会看这个文件的Hash
值.那么如果想要逃脱.你唯一的出路就是改变文件原有的二进制.(翻录\视频格式转换).
那么最简单的,就是一个压缩包,全部搞定
对称加密-常见算法
-
DES 数据加密标准(用得少,因为强度不够)
-
3DES 使用3个密钥,对相同的数据执行3次加密,强度增强
-
AES 高级密码标准。
- ECB(Electronic Code Book):电子密码本模式。每一块数据,独立加密。
最基本的加密模式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。
- CBC(Cipher Block Chaining):密码分组链接模式。使用一个密钥和一个初始化向量[IV]对数据执行加密。
明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。CBC
加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。
CBC
可以有效的保证密文的完整性,如果一个数据块在传递是丢失或改变,后面的数据将无法正常解密。
/**
* 终端测试指令
*
* DES(ECB)加密
* $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
*
* DES(CBC)加密
* $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
*
* AES(ECB)加密
* $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
*
* AES(CBC)加密
* $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
*
* DES(ECB)解密
* $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
*
* DES(CBC)解密
* $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
*
* AES(ECB)解密
* $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
*
* AES(CBC)解密
* $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
*
* 提示:
* 1> 加密过程是先加密,再base64编码
* 2> 解密过程是先base64解码,再解密
*/
具体见demo
对称加密-安全隐患
可以添加符号断点CCCrypt
查看被加密的字符串