IOS开发者学习笔记

密码学

2018-05-09  本文已影响8人  异想天不开_9950
三大类加密算法 算法特点 代表的算法
哈希(散列函数)算法 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(密钥)。它是怎么产生的,又是什么时候产生的呢?

注:第一次的第一个密钥来自于用户注册!

以后的每一次登录都需要走第3步对密码(HMAC & Key)加密后发送服务器,服务器对密码进行验证。可以看出来保存在本地的 Key 很关键!如果没有这个 Key 用户是不可能登录成功的!所以可以把 Key 放入钥匙串中,避免应用删除后,本地密钥也被删除!

image.png

那如果用户换了新手机该怎么办呢?

解决方案:

这种加密方式有什么好处呢?
我们都知道QQ有一个设备锁的功能。它的实现原理就是 HMAC 的实现原理!如果你在之前设置过设备锁,那么服务器不会立刻把 Key(密钥)给你,而是告诉你等待上一个设备进行验证。如果你的上一个设备不允许,那么这个 Key 是永远不会拿到的。

如果黑客拦截了你的请求,拿到了你的 HMAC 字符串,这样就可以模仿你给服务器发送请求,从而获取你的登录权限。那我们该如何保证用户的安全呢?

最常用以及最有效的解决方案:

这样可以保证,如果你发送网络请求,中间的延时能够有最少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. 今后的做法

采取封装的形式!

  1. 自定义一个函数,把明文A异或盐(从服务器请求或本地存储的都行,一个账号一个盐),得到密文B
  2. 把密文B丢给系统的加密算法,等到密文C
  3. 把密文C传给服务器

注:第1步中可以函数中再调函数,一层层加密。这样就加大了黑客解密的难度。

解密过程

解密:

  1. 密文C调用系统的解密算法,得到密文B
  2. 密文B同样异或盐,得到明文A

黑客也很难得到你的明文

作为黑客,由于他不知道你的逻辑,所以他想得到你的明文A是比较困难的。

  1. 首先,他会去 HOOK 系统的加密算法的函数,一个函数一个函数去 HOOK。
  2. 当他 HOOK 到之后,发现你调用了加密算法的函数,他会去看函数的返回值,对比这个函数的返回值(密文C)是不是你发给服务器的核心数据。
  3. 当他发现两者一样的时候,他就会去解密(密文C)。当他解密成功以为会拿到明文A,其实只是拿到了密文B,接下来他还需要把密文B解密。而这个过程,对我来说,我知道逻辑很好做,但是对于黑客来说,他只能去猜。是不是 HOOK 出了问题?是不是 HOOK 的方法出了问题?他就会这样一直怀疑,这样他想真正通过分析找到封装的函数的机率就非常低了。
上一篇下一篇

猜你喜欢

热点阅读