密码学
三大类加密算法 | 算法特点 | 代表的算法 |
---|---|---|
哈希(散列函数)算法 | 1. 算法公开 2. 对不同数据加密结果是定长的32位字符 3. 加密之后的数据是不可逆的 |
MD5 SHA 256/512 HMAC |
对称加密算法 | 1. 加密后可逆 2. 加密和解密使用同一个“密钥”(密钥的保密工作非常重要,密钥一般会定期换,密钥管理非常麻烦) 3. 加密效率高 |
DES 3DES AES |
非对称加密算法 | 1. 加密后可逆 2. 公钥和私钥(使用公钥加密,私钥解密;使用私钥加密,公钥解密) 3. 纯数学运算,加密效率非常低 |
RSA |
对称加密算法的两种加密方式 | 描述 |
---|---|
ECB | 电子代码本,就是说每一个数据块都是独立加密的 |
CBC | 密码块链,使用一个密钥和一个“初始化向量(IV)”对数据执行加密转换,每一个数据块的加密都与上一个数据块有关联 如果在传输数据的过程中,一个数据块被破坏了,那么整个数据都没法解密了 |
加密算法 | 应用场景 |
---|---|
MD5 | 1. 一般用来做密码加密 2. 版权问题(对比文件MD5值 ) 3. 搜索引擎(搜索iOS 密码学 与 密码学 iOS结果是一样的,原因:取MD5值,按位相加) 4. 百度云&360云盘秒传(对比文件MD5值) |
DES | 数据加密标准(用的少,因为强度不够) |
3DES | 使用3个密钥,对相同的数据执行3次加密,强度增强(更加用的少) |
AES | 高级加密标准,目前美国国家安全局使用的就是AES(用的少,因为强度不够) |
一、数据加密方法
以前对于用户密码一般使用MD5进行加密,但是现在单独使用MD5对用户密码加密已经不安全了!
现在的解决方案:
1. 加盐处理(可以保证MD5不被轻易的破解) — 早期的使用!
( 密码 + 盐 ) . md5
盐:静态字符串。一定要足够复杂,足够长!如:
static NSString *salt = @“SOFILKSFK92832349472JLF;p]qi3323hoos+_)(*^%’’//?adsofu8 {}SKDFJ@#%*(((&OKDKkdjfdjkdj”;
其实这种方法也不是足够安全,它有一个最大的弊端。盐:是固定写死的。写死在程序里面的。一旦盐泄漏,就不安全了!
2. HMAC 用一个密钥加密,然后做两次散列!-- 安全的做法!
pwd = [pwd hmacMD5StringWithKey:@“从服务器获取的key”]; //每一个账号对应着不同的key!
这个key是密钥!这个密钥是从服务器获取的!
HMAC加密关键点在于key(密钥)。它是怎么产生的,又是什么时候产生的呢?
注:第一次的第一个密钥来自于用户注册!
- 1)首先,客户端给服务器发送一个账号。
- 2)服务器拿到账号后会保存该账号,并对应着账号生成一个Key(密钥),紧接着服务器会把这个密钥返回给客户端。
- 3)客户端得到Key(密钥)后,会立刻将密钥保存在本地。接着使用 HMAC & Key 对密码进行加密,将加密后的32位字符串再发送给服务器。
((密码+key)).HMAC
- 4)服务器将HMAC之后的密码进行保存。
以后的每一次登录都需要走第3步对密码(HMAC & Key)加密后发送服务器,服务器对密码进行验证。可以看出来保存在本地的 Key 很关键!如果没有这个 Key 用户是不可能登录成功的!所以可以把 Key 放入钥匙串中,避免应用删除后,本地密钥也被删除!
image.png那如果用户换了新手机该怎么办呢?
解决方案:
- 重新根据你的账号发送给服务器,找服务器获取一次Key。
- 客户端拿到Key(密钥)后,将密钥保存在本地。接着使用 HMAC & Key 对密码进行加密,将加密后的32位字符串再发送给服务器。
- 服务器对密码进行验证。
这种加密方式有什么好处呢?
我们都知道QQ有一个设备锁的功能。它的实现原理就是 HMAC 的实现原理!如果你在之前设置过设备锁,那么服务器不会立刻把 Key(密钥)给你,而是告诉你等待上一个设备进行验证。如果你的上一个设备不允许,那么这个 Key 是永远不会拿到的。
如果黑客拦截了你的请求,拿到了你的 HMAC 字符串,这样就可以模仿你给服务器发送请求,从而获取你的登录权限。那我们该如何保证用户的安全呢?
最常用以及最有效的解决方案:
- 改第3步。客户端将HMAC加密后的密码+年月日时分,然后整体md5加密。再发送给服务器。
(((密码+key)).HMAC + “201805071622”).md5
- 服务器也通过此方法,比如
(((密码+key)).HMAC + “201805071623”).md5
后,得到的字符串与客户端发送的进行对比。如果对不上,服务器会立即换成上一分钟的时间再次进行对比。(((密码+key)).HMAC + “201805071622”).md5
这就是服务器的处理逻辑。
image.png
这样可以保证,如果你发送网络请求,中间的延时能够有最少61秒的时间,这样保证了正常的网络请求发送。这样的好处是如果一个黑客拦截了你的网络请求,他必须务必在120秒之内对其服务器进行访问。如果没访问,获取的网络请求的字符串就失效了。
这种方式的特点:
- 只有分钟没有秒
- 做到每次加密的结果是不一样的,加密的结果受时间的影响很大
很多公司都愿意把时间作为加密算法中的一个参数,这样保证了每一次加密结果都是不一样的。而且保证了可以和服务器做一个合适的验证。
二、数字签名原理
我们发送数据的时候,要保证数据在发送的过程中不能被篡改。所以就要求我们在发送数据的时候,对数据数字签名。
image.png
三、破解对称加密算法的思路
iOS系统库中定义了软件开发中常用的加解密算法,接口为C语言形式。具体包括了以下几个大类:
#include <CommonCrypto/CommonCryptor.h> //常用加解密算法
#include <CommonCrypto/CommonDigest.h> //摘要算法
#include <CommonCrypto/CommonHMAC.h>
#include <CommonCrypto/CommonKeyDerivation.h>
#include <CommonCrypto/CommonSymmetricKeywrap.h>
其中第一类常用加解密算法包含了AES、DES和已经废弃的RC4。第二类摘要算法包括如MD5、SHA等。
CCCrypt(<#CCOperation op#>, <#CCAlgorithm alg#>, <#CCOptions options#>, <#const void *key#>, <#size_t keyLength#>, <#const void *iv#>, <#const void *dataIn#>, <#size_t dataInLength#>, <#void *dataOut#>, <#size_t dataOutAvailable#>, <#size_t *dataOutMoved#>);
CC_MD5(<#const void *data#>, <#CC_LONG len#>, <#unsigned char *md#>);
CC_SHA256(<#const void *data#>, <#CC_LONG len#>, <#unsigned char *md#>):
像上面这些公开加密算法的函数,都是系统的函数。既然是系统的函数,那么 fishhook 就能够 HOOK 住。
调用系统加密函数
1. 以前的做法
一般像 RSA 公钥,这种非常重要核心的数据,你一般会采取什么方式保存在本地呢?很多人可能会使用钥匙串访问,因为钥匙串访问在本地,所以会感觉很安全。
但是,钥匙串访问也是调用的方法,一样传递的参数。与对称加密算法 CCCrypt 一样,钥匙串访问也是调用的系统函数,所以我们一样可以 HOOK。
假如:我们有一个 RSA 公钥,一个明文A。当我们调用 CCCrypt()
函数的时候,我们会把明文A参数传进去,然后进行加密,生成一个密文B。对于一个黑客来说,他没必要对密文B进行破解。他只需要 HOOK CCCrypt()
函数,拿到明文A。所以,我们要注意,在调用系统加密函数的时候,不要直接把核心数据丢进去。
2. 今后的做法
采取封装的形式!
- 自定义一个函数,把明文A异或盐(从服务器请求或本地存储的都行,一个账号一个盐),得到密文B
- 把密文B丢给系统的加密算法,等到密文C
- 把密文C传给服务器
注:第1步中可以函数中再调函数,一层层加密。这样就加大了黑客解密的难度。
解密过程
解密:
- 密文C调用系统的解密算法,得到密文B
- 密文B同样异或盐,得到明文A
黑客也很难得到你的明文
作为黑客,由于他不知道你的逻辑,所以他想得到你的明文A是比较困难的。
- 首先,他会去 HOOK 系统的加密算法的函数,一个函数一个函数去 HOOK。
- 当他 HOOK 到之后,发现你调用了加密算法的函数,他会去看函数的返回值,对比这个函数的返回值(密文C)是不是你发给服务器的核心数据。
- 当他发现两者一样的时候,他就会去解密(密文C)。当他解密成功以为会拿到明文A,其实只是拿到了密文B,接下来他还需要把密文B解密。而这个过程,对我来说,我知道逻辑很好做,但是对于黑客来说,他只能去猜。是不是 HOOK 出了问题?是不是 HOOK 的方法出了问题?他就会这样一直怀疑,这样他想真正通过分析找到封装的函数的机率就非常低了。