61cd2d0578472e78f0a0627d19ffd870
011 | 关于密码技术你需要了解的必备知识

安全方面的知识是必备的,而密码技术则是安全方面相对基础的知识,所以,自然也是需要掌握的。本篇文章我将分享下关于密码技术需要了解的必备知识有哪些,以及应该如何正确应用到实际项目中。

密码技术

前两天看了《得到》里吴军的新专栏《吴军的谷歌方法论》,提到了工程思维中“极限”的概念,我们作为软件工程师,也要牢记,任何计算机技术都有其极限,我们要认识到其极限,才能更快地看清楚问题的本质。

那么,回到密码技术上来,首先,我们必须清楚密码技术的极限在哪里。我们知道,密码技术是为了解决安全问题,再细化点,是为了解决信息安全问题。不同的密码技术,能够解决不同的信息安全问题,没有一种技术能解决所有信息安全问题。因此,我们为了能够解决尽量多的信息安全问题,都是通过组合多种密码技术来解决的。另外,高安全和高性能一般很难兼具,因此,也需要在两者间做好平衡。

对于密码技术所要解决的信息安全问题,除了信息保密问题,还涉及信息完整性校验、信息发布的不可抵赖性、以及在分布式计算中产生的来源于内部和外部的攻击的所有信息安全问题。为了解决这些信息安全问题的密码技术,从根本上来说,通常具有以下一个或多个特性:

  • 机密性:为了防止信息被窃听,因此需要对信息进行加密,对应的密码技术主要就是对称加密非对称加密
  • 完整性:为了防止信息被篡改,因此需要对信息进行完整性校验,对应的密码技术有单向散列函数、消息认证码、数字签名
  • 认证:为了防止攻击者伪装成真正的发送者,因此需要对信息进行鉴权,校验此消息是否来自合法的发送者,对应的密码技术有消息认证码、数字签名
  • 不可否认性:为了防止发送者发布信息后否认自己发布过,因此需要证据来证明信息是否由发送者发布,对应的密码技术为数字签名

上面已经提到了几种密码技术,包括对称加密、非对称加密、单向散列函数、消息认证码、数字签名,这些就是我们必须了解的几种密码技术。当然,这些可以说只是不同密码技术的类别,再看具体的算法,那就包括 AES、RSA、MD5、SHA1、SHA256、HMAC 等。有些对密码技术不了解的人,还会将 BASE64 也理解为一种加解密的密码技术。但实际上,BASE64 只是一种编码方式,本质上其实和 ASCIIUTF-8 编码类似,主要用途就是将不可打印的二进制数据编码为可打印的字符串,它并不具备以上密码技术的四个特性中的任何一个。

对称加密

对消息加密和解密使用相同密钥的加密算法就叫对称加密,也称为私钥加密、密钥加密。常用的对称加密算法有:DES、3DES、AES、Blowfish、RC4、RC5、RC6 等,现在的标准是 AES,也是目前使用最广泛的对称加密算法,也是我们必备掌握的算法之一。

AES 是一种分组密码,即将明文消息拆分为一定长度的N个分组,然后对每个分组进行加密。AES 的分组长度固定为 128 比特,而密钥可以是 128/192/256 比特。既然是固定长度的分组,那我们要加密任意长度的明文,就涉及到如何将多个分组进行迭代加密的问题,因此,就有了分组模式。常用的分组模式有:ECB、CBC、CFB、OFB、CTR 等。最常用的是 ECB 和 CBC 模式,因此,需要了解下这两种模式的用法和区别。

ECB 全称为 Electronic CodeBook电子密码本模式,是最简单的一种模式,它直接将明文分割成多个分组并逐个加密,如下图:

这种模式的优点就是简单、快速,加密和解密都支持并行计算。而缺点也比较明显,因为每个明文分组都各自独立地进行加密和解密,如果明文中存在多个相同的明文分组,则这些分组最终会被转换为相同的密文分组。这样一来,只要观察一下密文,就可以知道明文中存在怎样的重复组合,并可以以此为线索来破译密码。另外,攻击者可以通过改变密文分组的顺序,或删除密文分组,或替换掉密文分组,就可以达到对明文操纵的目的,而无需破译密码。在实际应用中,很少需要进行并行计算的加解密场景,因此,一般情况下不会采用这种分组模式,而更推荐采用 CBC 模式。

CBC 全称为 Cipher Block Channing密文分组链接模式,是将前一个密文分组与当前明文分组的内容混合起来进行加密的,如下图:

在 CBC 模式中,首先将明文分组与前一个密文分组进行 XOR 运算,然后再进行加密。加密第一个明文分组时,由于不存在“前一个密文分组”,因此需要事先准备一个长度为一个分组的比特序列来代替“前一个密文分组”,这个比特序列称为初始化向量(initialization vector),通常缩写为 IV。CBC 模式避免了 ECB 模式的弱点,明文的重复排列不会反映在密文中。不过,相比 ECB 模式,CBC 模式多了一个初始化向量IV

另外,当最后一个明文分组的内容小于分组长度时,需要用一些特定的数据进行填充,填充方式也有很多种,常用的有两种:PKCS#5PKCS#7。需要注意的就是,不同编程语言使用的填充方式可能会不同。比如,Java 是使用 PKCS#5,而 iOS 的 Objective-C 和 Swift 则采用 PKCS#7。不过,对于 AES 来说,两种填充方式是一样的。

在实际应用中,我们一般都是在前端对密码或其他敏感数据进行加密,然后在后端进行解密。因为前后端涉及到不同语言的实现,为了保证前后端经过加解密后的结果一致,有几个参数是需要保持一致的:

  • 密钥:密钥都要使用同一个,这点基本没有疑问,但需要注意的就是,密钥长度需要统一为 128/192/256 比特,即 16/24/32 字节。
  • 分组模式:分组模式推荐统一为 CBC 模式,且要显式声明,因为不同语言的默认分组模式可能会不同。
  • 初始化向量:加密和解密时的初始化向量 IV 也是要一致的,同样也不要使用默认设置,而要显式定义。
  • 填充方式:Java 采用 PKCS5Padding,iOS 和 JavaScript 采用 PKCS7,对于 AES 来说,两者是一样的。

还有一点也需要注意,AES 算法本身操作的都是 byte 字节数组,因此,加密后一般会使用 BASE64 编码将 byte 数组转为字符串,而解密之前则先用 BASE64 解码将字符串转回 byte 数组。

使用对称加密最关键的就是要保证密钥的安全,一般不建议直接在网络上传输密钥,另外,在客户端也要做好密钥的安全存储。

非对称加密

非对称加密也称公钥加密,使用了一对密钥,用公钥进行加密,再用配对的私钥进行解密。公钥是公开的,而私钥是保密的。相比对称加密安全性提高了,但牺牲了性能,加解密的速度慢了几个数量级,消息越长,加密和解密的速度越慢。

使用最广泛的非对称加密算法就是 RSA,其原理是利用了大整数质因数分解问题的困难度,加密和解密其实就是非常简单的两条公式:

  • 加密:密文 = 明文^E mod N
  • 解密:明文 = 密文^D mod N

即是说,加密就是对明文的 E 次方后除以 N 求余数的过程,其中 E 和 N 的组合就是公钥,即公钥 = (E, N)。而解密过程就是对密文进行 D 次方后除以 N 得到余数,即是明文,D 和 N 的组合就是私钥,即私钥 = (D, N)。公钥和私钥共有的 N 称为 module,即模数,E 和 D 则分别是公钥指数和私钥指数。因为 RSA 是基于以上数学问题的,所以其明文、密钥和密文都是数字,我们平时看到的字符串其实都是二进制表示的数字经过 BASE64 编码的。

top Created with Sketch.