浅谈iOS中常用加密算法的使用

3,520 阅读7分钟

 以前如果我们忘记了登录密码,通常可以通过“找回密码”这样的方式拿回密码,那说明你的隐私数据在他们的数据库中是明文保存的,现在请切记:如果哪个平台还有这样的方式请立刻马上注销你的账号,并避免在任何其他平台使用这个平台使用过的密码。请坚信:在网络世界中,只要是明文存在或可逆的东西,都是不安全的。没有哪家公司会告诉你他们的数据库被拖库过,你更无法想象现在的黑色产业早已让你毫无隐私。

 千万别一个密码走天下,一定要定期改密码!

 道高一尺魔高一丈,对用户隐私及一些敏感数据的保护越来越重要,在iOS中,苹果封装了Security.framework、CommonCrypto.framework这两个保护信息安全的库,为我们提供了安全相关的通用API:

  • RSA:公私钥的生成、公钥加密、私钥解密、私钥签名、公钥验签功能,证书信息的读取,以及密钥在KeyChain中存储,查找,删除等功能
  • 哈希:SHA1、SHA224、SHA256、SHA384、SHA512 MD2、MD4、MD5
  • 对称加密:DES、3DES、AES

 这一篇文章,我们就以“用户输入密码,登录,服务端验证用户信息,用户上传隐私数据”这个常见场景为例,分享一些密码学常识和加密时常用的防破解技巧,至于上述算法相关API的使用,文末我会附上iOS中所有常用加密API使用的demo,这里就不浪费篇幅贴代码了。先说两个保护用户隐私的原则:

  • 网络上不允许明文传递用户隐私信息
  • 本地不允许明文保存用户隐私信息

 再了解下几种算法的特点:

对称加密

  • 加密解密共用一个密钥
  • DES 数据加密标准,安全强度不够已经很少用了
  • 3DES 使用三个密钥对相同的数据执行三次加密 强度略高,但密钥的保护一直是个隐患所以也不常用
  • AES 高级密码标准 用得最多
  • 两种常用加密模式:
    • ECB:
       最基本的加密方式,无初始向量,相同的明文永远生成不变的密文,容易受到密码本重放攻击,很少用
    • CBC:
       明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。
       可以有效的保证密文的完整性,如果一个数据块在传递是丢失或改变,后面的数据将无法正常解密。

RSA

关于RSA相关知识请参考:
非对称加密--RSA原理浅析
RSA的主场-证书签名之OpenSSL演示

这里不再赘述。

哈希算法

也就是常说的散列函数,严格意义上它并不是一种加密算法,但它常常与加密算法一起出现,作为一种组合方式。哈希具有以下特点:

  • 算法是公开的
  • 对相同的数据运算,得到的结果是一样的
  • 同一算法对不同的数据运算,得到的结果长度是固定的,如MD5的结果一定是128bit,32个字符(16进制表示),所以散列碰撞是必然的偶然
  • 不可逆,但是可以通过彩虹表反查询
  • 通常作为信息“指纹”--信息摘要,用来做数据识别(版权、搜索引擎、数字签名等)。

实际应用

 知道了每种算法的特点,回到应用场景:用户输完密码点击登录时,我们如何保证用户信息是足够安全的呢?

  • 对称加密:密钥传输有隐患,且在客户端加密前和服务端解密后会出现明文,不安全。
  • RSA:安全性高,网络劫持很难破解,但是服务端拿到客户端加密后的密文怎么办呢?用私钥解密,解密之后拿到明文信息?大忌,没有哪个服务端是安全的,更没法保证数据库人员的个人泄露用户信息。不可取。
  • 哈希:
    • 直接MD5?用户输入常规组合概率很大,暴力破解风险很高,不可取。本地加盐,很变态的盐?安全性有一定保障,缺点是盐写死在程序里了,写代码的人也有泄露的可能性,一旦泄漏结果是毁灭性的,不可取。
    • HMAC:Keyed-Hashing for Message Authentication,这是一种使用单向散列函数来构造消息认证码的方案,而不是算法。
        在第一次注册时,服务端下发一个随机密钥 n,这个密钥会在客户端和服务端都保存一份(支持服务端更新),客户端的 n 用作以后每次登录时的“盐”参与第一次散列运算,并将第一次散列运算的结果 s 发给服务端作为用户密码信息保存到数据库中,这样用户的真实密码无论是客户端还是服务端都不知道,也不存在数据库被拖库泄露的问题。服务端保存的 n 用于当用户换设备登录或卸载重新装时验证通过后再次将 n 下发给客户端保存。
       用户每次登录时,服务器会再动态下发一个随机值作为密钥,并在会话中记下这个随机值 r,客户端先用本地保存的 n 对用户密码做散列运算得到 s ,再用 r 对 s 做一次MAC(Message Authentication Codes)运算并将运算结果发送给服务端,服务端也从数据库中取出用户的密码散列值做同样的运算,并将结果与客户端进行对比。为了防止网络中间人攻击,还需将时间戳(服务器时间,一般精确到分钟)参与校验,黑客就很难破解了。这是目前最主流的安全方案。

 现在用户登录成功,现在要上传一份敏感数据,我们如何保证数据的完整性呢?结合上面的分析,推荐AES的CBC加密方式,安全性高,还能保证完整性,数字签名同样也可以验证数据完整性,用RSA对数据的hash值进行加密,服务端接收完数据后,用私钥解密得到hash值,与接收数据的hash值作比对。

补充:

iOS中常见加密算法的使用:EncryptDemo
在Demo中,对称加密AES的加密解密函数:

CCCryptorStatus CCCrypt(
    CCOperation op,         /* kCCEncrypt, etc. */
    CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
    CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
    const void *key,
    size_t keyLength,
    const void *iv,         /* optional initialization vector */
    const void *dataIn,     /* optional per op and alg */
    size_t dataInLength,
    void *dataOut,          /* data RETURNED here */
    size_t dataOutAvailable,
    size_t *dataOutMoved)
    API_AVAILABLE(macos(10.4), ios(2.0));  

调用CCCrypt时,用户敏感数据不要直接作为参数传递,否则逆向很容易hook到,通常的做法是对敏感数据做异或、加盐等处理,具体根据需要自己设计。

iOS app签名机制详解 推荐阅读:
iOS应用签名(上)
iOS应用签名(下)

iOS中对钥匙串的操作推荐:SSKeyChain

实践出真知,我们下篇再会~

老规矩,有错误请积极指正,有问题请踊跃留言。

更多一手好文更新,请关注我的个人微信公众号:面向未来编程
撒花✧(≖ ◡ ≖✿)