iOS加密详解

1,049 阅读10分钟

在开发应用的时候,数据的安全性至关重要。我们会要求开发者不允许明文传输用户的隐私数据,同时也不允许明文保存用户的隐私数据;这就需要我们去对敏感的数据进行加密处理。

常见的加密算法

  • 哈希(散列)函数:MD5、SHA
  • 对称加密算法:DES、3DES、AES
  • 非对称加密算法:RSA

特点:

  • 对输入信息生成唯一的128位散列值(32个字符)
  • MD5加密后的结果是不可逆的
  • 同一个数据加密之后得到的结果是一样的

所有的数据(视频、音频、文件、只要存在于硬盘或内存中的)都是可以被MD5加密的,得到的都是32个字符。 上代码:

- (NSString *)md5String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, (CC_LONG)strlen(str), buffer);
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}

封装好的在这里:NSString-Hash

但是这是不安全的,相对来说比较容易破解:MD5解密网站

传统方法是加盐(Salt):在明文的固定位置插入位数足够多、足够复杂的随机串,然后再进行MD5。

NSString *salt = @"fdsfjf)*&*JRhuhew7HUH^&udn&&86&*";
NSString *str = @"123456";   
str = [str stringByAppendingString:salt];
str = [str md5String];
NSLog(@"%@",str);

缺点:盐是固定不变的,一旦泄露后果不堪设想;使用加盐通过MD5解密之后,很容易发现规律从而破解。

image.png

解决方案

HMAC :使用一个密钥加密并且两次的散列!

以用户账号登录注册为例

  • 注册: 1.客户端向服务器发起注册请求,这时服务器生成一个密钥key(并保存),然后将密钥返回给客户端。 2.客户端根据密钥对密码进行HMAC加密生成密文,传给服务器,服务器保存(不允许明文保存用户的隐私信息)。 3.服务器返回注册成功后,客户端将密钥保存到手机钥匙串(减少密钥传递次数,提高安全性)。

  • 登录: 1.客户端读取手机钥匙串中的密钥,对密码进行HMAC加密后,向服务器发出登录请求。 2.服务器根据账号读取数据库中的密文与客户端提交的进行比较。 上代码:

- (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)
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}

引申:可以利用这个做出类型于设备锁或QQ手机令牌的功能,目的就是为了在他人设备上无法登录自己的账号。这里说下大致的流程,在客户端发出登录请求时,在手机钥匙串读取密钥,当这个密钥不存在的时,就说明是在他人设备上操作的,这时可以利用推送通知或短信告诉自己,是否允许他人设备登录,只允许此次登录还是授权永久登录。如果仅登陆一次则不保存密钥到钥匙串,下次登录重复以上操作;如果授权永久登录可以再他人设备保存密钥。

那么这样就安全了吗?no!

如果在第2步中,拦截post内容获取加密后的密文,再模拟客户端向服务器发出请求,就成功黑了!

再次提高安全性:添加时间戳

  • 第一步: 客户端将HMAC得到的数据拼接当前服务器时间,再用MD5加密。 即(HMAC+201802271633).md5String,将加密后的数据post到服务器。

注:201802271633 须为当前服务器时间,避免客户端时间不统一。

  • 第二步: 服务器开始验证:根据账号在数据库中读取HMAC,将当前服务器时间拼接后,再用MD5加密,得到32位字符与客户端提交的32位字符进行比较。这里会有两种情况,1.服务器拼接的时间与客户端拼接的时间一致,得到相同的密文,则通过验证;2.服务器拼接的时间与客户端拼接的时间不一致,得到的密文不相同。这是服务器就拼接上一个时间,即:客服端密文是:(HMAC+201802271633).md5String,服务器第一次拼接时间密文是:(HMAC+201802271634).md5String。两者不一致,服务器第二次拼接上一个时间段密文:(HMAC+201802271633).md5String,一致则通过。

进行这样的操作就是让客户端发出的请求的时间有效性只维持1分钟,如果还觉得不安全可以再拼接时间的时候添加秒,进一步缩短时间的有效性,以提高安全性。

哈希的用途

哈希主要用于验证,就像人的指纹一样。涉及到验证的部分一般都可以使用Md5,如:向百度云上传文件,百度将每个文件都进行MD5,将你上传的文件MD5与已有的比对,加入存在说明你上传的文件库里已经有了,直接秒传。一般来说相同的文件库里面只会保存一份。

哈希破解(散列碰撞):不同的N多种数据哈希之后得到相同的结果

上面说过不同的数据MD5后得到的应该是不同的32位字符,但是32位字符排列组合的个数是有限的,但是数据是无限的,比如自然数字。对无限的数据MD5得到有限个32位字符,其中肯定是有重复的。

对称加密算法

对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。

即: 明文——>加密——>密文 密文——>解密——>明文

特点:算法公开、计算量小、加密速度快、加密效率高。 缺点:密钥管理困难,使用成本较高,双方都使用同样的密钥,安全性得不到保证。

非对称加密算法 ——(RSA)现代加密算法

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。即:

1、A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥

2、A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。

3、A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。

4、A将这个消息发给B(已经用B的公钥加密消息)。

5、B收到这个消息后,B用自己的私钥解密A的消息。其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。

特点:算法强度复杂、安全性较高。 缺点:由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。

RSA

RSA算法基于一个十分简单的数论事实:将两个大质数(素数)相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。比如:取两个简单的质数:89、97,得到两者乘积很简单8633;但是要想对8633进行因式分解,其工作量成几何增加。

数字签名

场景: 早上买杯奶茶,使用店家的app支付可以打5折;一杯奶茶10元,你用店家的app支付了5元,马上收到消费5元的通知。 看似一切正常,但是黑客拦截并获取客户端发送的请求支付的信息,将需要支付的5元改成50元并发送,终端收到支付50元的请求,扣款50元并将扣款信息返回给客户端,黑客再次拦截扣款信息,将已扣款50元改成已扣款5元后发送给客户端。 一来一回你已经在不知不觉中损失了45元。

image.png

移动支付、金融流通越来越频繁,如何避免这样的问题,这就需要对敏感数据进行数字签名。

数字签名(又称公钥、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。

将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。

数字签名是个加密的过程,数字签名验证是个解密的过程。

image.png

  • 客户端:

    • 将敏感信息进行对称或非对称加密得到加密过得数据报文;
    • 将数据报文再进行一下HASH算法加密得到32位的HSAH值;
    • 将32位HASH值进行RSA算法加密得到签名;
    • 将签名和数据报文打包组合发送给服务端;
  • 服务端:

    • 将接收到的签名用私钥解密得到32位的HASH值;
    • 将接收到的数据报文按照客户端相同的操作进行HASH算法,得到32位HASH值;
    • 判断两个HASH是否相同,如相同则表示数据报文是安全的;
    • 将数据报文解密得到需要的原始数据;

总结

攻防无小事,重要的是对算法的运用。加密算法的种类是固定的,根据自己的产品业务去选择适合的算法组合才是最重要的。


个人浅见,有误的地方欢迎指正