把《图解密码技术》读薄

810 阅读18分钟

前言

《图解密码技术》一书介绍了很多关于密码的知识,通读一遍需要不少时间。为了方便学习,我对书中关键的部分进行了总结,希望可以提高大家的学习效率。如果想对本文中的某些内容进行深入研究,您可以查阅原书。

历史上的密码

凯撒密码

凯撒密码是通过将明文中所使用的字母表按照一定的字数“平移”来进行加密和解密的。

简单替换密码

简单替换密码是将明文中所使用的的字母表替换为另一套字母表的密码。

Enigma

Enigma是第二次世界大战中德国使用的一种密码机,它是一种由键盘、齿轮、电池、和灯泡所组成的机器,通过这一台机器就可以完成加密和解密两种操作。

现代计算机之父阿兰•图灵曾是破译德国密码机团队的一员。图灵在1940年研制出了用于破译Enigma的机器。

对称密码

对称密码是一种用相同的密钥进行加密和解密的技术,用于确保消息的机密性。


对称密码.png
一次性密码本

只要通过暴力破解法对密钥空间进行遍历,无论什么密文总有一天也都能够被破译。然而一次性密码本却是一个例外,即便使用暴力破解法遍历整个密钥空间,一次性密码本也绝对无法被破译。
一次性密码本是一种非常简单的密码,它的原理是“将明文与一串随机的比特序列进行XOR(异或)运算”。
在一次性密码本中,由于我们无法判断得到的是不是正确的明文,因此一次性密码本是无法破译的。
由于一次性密码本存在配送、保存、重用、同步等方面的问题,所以几乎没有人应用一次性密码本,因为它是一种非常不实用的密码。

DES

DES(Data Encryption Standard)是1977年美国联邦信息处理标准中所采用的一种对称码。
DES是一种将64比特的明文加密成64比特的密文的对称密码算法,它的密钥长度是56比特。尽管从规格上来说,DES的密钥长度是64比特,但由于每隔7比特会设置一个用于错误检查的比特,因此实质上其实密钥长度是56比特。

由于DES的密文可以在短时间内被破译,因此除了用它来解密以前的密文以外,现在我们不应该使用DES了。

三重DES

三重DES是为了增加DES的强度,将DES重复3次所得到的一种密码算法,也称为TDEA,通常缩写为3DES。

尽管三重DES目前还被银行等机构使用,但其处理速度不高,除了特别重视向下兼容性的情况以外,很少被用于新的用途。

AES

AES(Advanced Encryption Standard)是取代其前任标准(DES)而成为新标准的一种对称密码算法(Rijndael)。
Rijndael是由比利时密码学家Joan Daemen和Vincent Rijmen设计的分组密码算法,于2000年被选为新一代的标准密码算法——AES。
Rijndael的分组长度和密钥长度可以分别以32比特为单位在128比特到256比特的范围内进行选择。不过在AES的规格中,分组长度固定为128比特,密钥长度只有128、192、和256比特三种。

在对称密码的算法方面,目前主要使用的是AES,因为它安全、快速、而且能够在各种平台上工作。尽管对称密码能够确保消息的机密性,但需要解决将解密秘钥配送给接收者的密钥配送问题

分组密码的模式

DES和AES都属于分组密码,它们只能加密固定长度的明文。如果需要加密任意长度的明文,就需要对分组密码进行迭代,而分组密码的迭代方法就称为分组密码的模式。

ECB模式

Electronic CodeBook Mode(电子密码本模式)。在ECB模式中,将明文分组加密之后的结果直接成为密文分组。

由于安全性最差已不推荐使用

CBC模式

Cipher Block Chaining Mode(密文分组链接模式)。在CBC模式中,首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密。

初始化向量

当加密第一个明文分组时,由于不存在“前一个密文分组”,因此需要事先准备一个长度为一个分组的比特序列来代替“前一个密文分组”,这个比特序列称为初始化向量(Initialization Vector),通常缩写为IV

CFB模式

Cipher FeedBack Mode(密文反馈模式)。在CFB模式中,首先将前一个密文分组进行加密,最后将加密后的密钥流与明文分组进行XOR运算得到密文分组。

OFB模式

Output-Feedback Mode(输出反馈模式)。在OFB模式中,逐次的对密钥流进行加密后得到流密码,与明文分组进行XOR运算得到密文分组。

CTR模式

CounTeR Mode(计数器模式)。在CTR模式中,通过将逐次累加的计数器进行加密来生成密钥流的流密码,然后与明文分组进行XOR运算得到密文分组。

公钥密码

公钥密码(非对称密码)中,密钥分为加密密钥和解密密钥两种。发送者用加密密钥对消息进行加密,接收者用解密密钥对密文进行解密。


公钥密码.png
RSA

RSA是一种公钥密码算法,它的名字是由它的三位开发者,即Ron Rivest、Adi Shamir和Leonard Adleman的姓氏的首字母组成的(Rivest-Shamir-Adleman)。

RSA的加密是求“E次方的 mod N”,而解密则是求“D次方的 mod N”

密文 = 明文^E mod N

明文 = 密文^D mod N
EIGamal方式

EIGamal方式是由Taher EIGamal设计的公钥算法。RSA利用了质因数分解的困难度,而EIGamal方式则利用了mod N 下求离散对数的困难度。

Rabin方式

Rabin方式是由M.O.Rabin设计的公钥算法。Rabin方式利用了mod N下求平方根的困难度。

椭圆曲线密码

椭圆曲线密码(Elliptic Curve Cryptography,ECC)是最近备受关注的一种公钥密码算法。它的特点是所需的密钥长度比RSA短。
椭圆曲线密码是通过将椭圆曲线上的特定点进行特殊的乘法运算来实现的,它利用了这种乘法运算的逆运算非常困难这一特性。

使用公钥密码能够解决密钥配送问题。公钥密码是密码学界的一项革命性发明,现代计算机和互联网所使用的密码技术都得益于公钥密码。
尽管公钥密码能够解决对称密码中的密钥交换问题,但存在通过中间人攻击被伪装的风险,因此需要对带有数字签名的公钥进行认证
即使已经有了公钥密码,对称密码也不会消失。公钥密码的运行速度远远低于对称密码,因此在一般的通信过程中,往往会配合使用这两种密码,即用对称密码提高处理速度,用公钥密码解决密钥配送问题。这样的方式称为混合密码系统。

单向散列函数

单向散列函数有一个输入和一个输出,其中输入称为消息(message),输出称为散列值(hash code)。单向散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性。
散列值的长度和消息的长度无关。无论消息是1比特,还是100MB,甚至是100GB,单向散列函数都会计算出固定长度的散列值。
以SHA-256单向散列函数为例,它所计算出的散列值的长度永远是256比特(32字节)。
为了能够确认完整性,消息中哪怕只有1比特的改变,也会产生不同的散列值。
单向散列函数输出的散列值也称为消息摘要(message digest)或者指纹(fingerprint)


单向散列函数根据消息的内容计算出散列值.png
MD4、MD5

MD(Messge Digest)4是由Rivest于1990年设计的单向散列函数,能够产生128比特的散列值。现在它已经不安全了。
MD(Messge Digest)5是由Rivest于1991年设计的单向散列函数,能够产生128比特的散列值。MD5的强抗碰撞性已经被攻破。也就是说,现在已经能够产生具备相同散列值的两条不同的消息,因此它也不安全了。

SHA-1、SHA-256、SHA-384、SHA512

SHA-1是由NIST(美国国家标准技术研究所)设计的一种能够产生160比特的散列值的单向散列函数。现在已不推荐使用
SHA-256、SHA-384、SHA512都是由NIST设计的单向散列函数,它们的散列值长度分别为256比特、384比特、和512比特。这些单向散列函数合起来统称SHA-2。
SHA-1的强抗碰撞性已于2005年被攻破,不过,SHA-2还尚未被攻破。

RIPEMD-160

RIPEMD-160是于1996年由Hans Dobbertin、Antoon Bosselaers和Bart Preneel设计的一种能够产生160比特的散列值的单向散列函数。RIPEMD-160是欧盟RIPE项目所设计的RIPEMD单向散列函数的修订版。
RIPEMD的强抗碰撞性已经于2004年被攻破,但RIPEMD-160还尚未被攻破。比特币中使用的就是RIPEMD-160。

SHA-3

SHA-3(Secure Hash Algorithm-3)是一种作为新标准发布的单向散列函数算法,用来替代在理论上已被找出攻击方法的SHA-1算法。
SHA-3的标准是Keccak算法。

Keccak

Keccak是一种被选定为SHA-3标准的单向散列函数算法。
Keccak可以生成任意长度的散列值,但为了配合SHA-2的散列值长度,SHA-3标准中共规定了SHA3-224、SHA3-256、SHA3-384、SHA3-512这4种版本。

单向散列函数能够辨别出“篡改”,但无法辨别出“伪装”,这时就需要进行认证

消息认证码

消息认证码(Message Authentication Code)是一种确认完整性并进行认证的技术,简称为MAC。
消息认证指的是“消息来自正确的发送者”这一性质。
消息认证码的输入包括任意长度的消息和一个发送者与接受者之间共享的密钥,它可以输出固定长度的数据,这个数据成为MAC值。
要计算MAC必须持有共享密钥,没有共享密钥的人就无法计算MAC值,消息认证码正是利用这一性质来完成认证的。此外,和单向散列函数的散列值一样,哪怕消息中发生1比特的变化,MAC值也会产生变化,消息认证码正是利用这一性质来确认完整性的。
消息认证码可以说是一种与密钥相关联的单向散列函数。
消息认证码可以使用单向散列函数和对称密码等技术来实现。


单向散列函数与消息认证码的比较.png

消息认证码的使用步骤.png
HMAC

HMAC是一种使用单向散列函数来构造消息认证码的方法,其中HMAC的H就是Hash的意思。

消息认证码也不能解决所有的问题,例如“对第三方证明”,和“防止否认”,这两个问题就无法通过消息认证码来解决。

数字签名

消息认证码之所以无法防止否认,是因为消息认证码需要在发送者和接收者两者之间共享一个密钥。
数字签名是一种能够对第三方进行消息认证,并能够防止通信对象作出否认的认证技术。
数字签名中也同样会使用公钥和私钥组成的密钥对,不过这两个密钥的用法和公钥密码是相反的,即用私钥加密相当于生成签名,而用公钥解密则相当于验证签名。


生成签名和验证签名.png

实现数字签名使用的算法如下:

RSA

RSA是一种公钥密码算法,它的名字是由它的三位开发者,即Ron Rivest、Adi Shamir和Leonard Adleman的姓氏的首字母组成的(Rivest-Shamir-Adleman)。

用RSA生成签名和验证签名的过程可用下列公式来表述:

签名 = 消息^D mod N

由签名得到的消息 = 密文^E mod N
EIGamal

EIGamal方式是由Taher EIGamal设计的公钥算法。利用了mod N 下求离散对数的困难度。EIGamal方式可以被用于公钥密码和数字签名。

DSA

DSA(Digital Signature Algorithm)是一种数字签名算法,是由NIST于1991年制定的数字签名规范。
DSA是Scnorr算法与EIGammal方式的变体,只能被用于数字签名。

ECDSA

ECDSA(Elliptic Curve Digital Signature Algorithm)是一种利用椭圆曲线密码来实现的数字签名算法。

Rabin方式

Rabin方式是由M.O.Rabin设计的公钥算法。利用了在mod N下求平方根的困难度。Rabin方式可以被用于公钥密码和数字签名。

用数字签名既可以识别出篡改和伪装,还可以防止否认,但是无法确认用于验证签名的公钥属于真正的发送者的。
要确认公钥是否合法,可以对公钥施加数字签名,这就是证书

证书

公钥证书(Public-Key Certificate,PKC)其实和驾照很相似,里面记有姓名、组织、邮箱、地址等个人信息,以及属于此人的公钥,并由认证机构(Certification Authority,CA)施加数字签名。只要看到公钥证书,我们就可以知道认证机构认定该公钥的确属于此人。公钥证书也简称为证书。
认证机构就是能够认定“公钥确实属于此人”并能够生成数字签名的个人或者组织。


消息发送者利用认证机构向消息接收者发送密文.png
X.509

X.509是一种证书生成和交换的标准规范。

PKI

PKI(Public-Key Infrastructure)是为了能够更有效地运用公钥而制定的一系列规范和规格的总称。X.509也是PKI的一种。

密钥

各种不同的密钥
1.对称密码的密钥与公钥密码的密钥
2.消息认证码的密钥与数字签名的密钥
3.用于确保机密性的密钥与用于认证的密钥
4.会话密钥与主密钥

当我们访问以 https:// 开头的网页时,Web服务器和浏览器之间会进行基于SSL/TLS的加密通信。在这样的通信中所使用的密钥是仅限于本次通信的一次性密钥,下次通信时就不能使用了。像这样每次通信只能使用一次的密钥称为会话密钥(session key)。
相对于每次通信都更换的会话密钥,一直被重复使用的密钥称为主密钥(master key)。

5.用于加密内容的密钥与用于加密密钥的密钥

一般来说,加密的对象是用户直接使用的消息(内容),这样的情况下所使用的密钥称为CEK(Contents Encrypting Key);相对地,用于加密密钥的密钥则称为KEK(Key Encrypting Key)。
上面提到的会话密钥都是被作为CEK使用的,而主密钥则是被作为KEK使用的。


CEK与KEK.png
Diffe-Hellman密钥交换

Diffe-Hellman密钥交换是1976年由Whitfield Diffe和Martin Hellman共同发明的一种算法。使用这种算法,通信双方通过交换一些可以公开的信息就能够生成出共享的秘密数字,而这一秘密数字就可以被用作对称密码的密钥。


Diffee-Hellman密钥交换.png
椭圆曲线Diffe-Hellman密钥交换

Diffe-Hellman密钥交换是利用“离散对数问题”的复杂度来实现密钥的安全交换的,如果对“离散对数问题”改为“椭圆曲线上的离散对数问题”,这样的算法就称为椭圆曲线Diffe-Hellman密钥交换。
椭圆曲线Diffe-Hellman密钥交换能够用较短的密钥长度实现较高的安全性。

基于口令的密码(PBE)

基于口令的密码(Password Based Encryption,PBE)就是一种根据口令生成密钥并用该密钥进行加密的方法。其中加密和解密使用同一个密钥。
其中密钥(KEK)是由口令和盐(由伪随机数生成器生成的随机数)一起输入的单向散列函数。
盐是用来防御字典攻击的。字典攻击是一种事先进行计算并准备好候选密钥列表的方法。


PBE加密.png

PBE解密.png

随机数

随机数的用处
  • 生成密钥:用于对称密码和消息认证码。
  • 生成密钥对:用于公钥密码和数字签名。
  • 生成初始化向量(IV):用于分组密码的CBC、CFB和OFB模式。
  • 生成nonce:用于防御重放攻击以及分组密码的CTR模式等。
  • 生成盐:用于基于口令的密码等。
随机数的性质
  • 随机性(弱伪随机数)
  • 不可预测性(强伪随机数)
  • 不可重现性(真随机数)
随机数生成器

通过硬件生成的随机数列,是根据传感器收集的热量、声音的变化等事实上无法预测和重现的自然现象信息来生成的。像这样的硬件设备就称为随机数生成器。

伪随机数生成器

而可以生成随机数的软件则称为伪随机数生成器。因为仅靠软件无法生成真随机数,因此要加上一个“伪”字。

SSL/TLS

SSL(Secure Sockets Layer,安全套接层)是1994年由网景公司(Netscape)设计的一种协议,并在该公司的Web浏览器上进行了实现。随后,很多Web浏览器都采用了这一协议,使其成为了事实上的行业标准。SSL已经于1995年发布了3.0版本,但在2014年,SSL3.0协议被发现存在可能导致POODLE攻击的安全漏洞,因此SSL3.0已经不安全了。

TLS(Transport Layer Security ,传输层安全)是IETF在SSL3.0的基础上设计的协议。在1999年作为RFC2246发布的TLS1.0,实际上相当于SSL3.1。
2006年,TLS1.1以以RFC4346的形式发布,这个版本中增加了针对CBC攻击的策略并加入了AES对称加密算法。TLS1.2中新增了对GCM、CCM认证加密的支持,此外还新增了HMAC-SHA256,并删除了IDEA和DES,将伪随机函数(PRF)改为基于SHA-256来实现。

SSL/TLS的工作

我们想要实现通过本地的Web浏览器访问网络上的Web服务器,并进行安全通信。举个例子来说就是,用户希望通过Web浏览器向xx银行发送信用卡号。在这里,我们有几个必须要解决的问题。

(1)用户的信用卡号和地址在发送到xx银行的过程中不能被窃听。
(2)用户的信用卡号和地址在发送到xx银行的过程中不能被篡改。
(3)确认通信对方的Web服务器是真正的xx银行。

在这里,(1)是机密性问题,(2)是完整性问题,(3)则是认证的问题。
要确保机密性,可以使用对称密码。由于对称密码的密钥不能被攻击者预测,因此我们使用伪随机数生成器来生成密钥。若要将对称密码的密钥发送给通信对象,可以使用公钥密码或者Diffie-Hellman密钥交换。
要识别篡改,对数据进行认证,可以使用消息认证码。消息认证码是使用单向散列函数来实现的。
要对通信对象进行认证,可以使用对公钥加上数字签名所生成的证书。

SSL/TLS就是将对称密码、公钥密码、单向散列函数、消息认证码、伪随机数生成器、数字签名等技术相结合来实现安全通信的。