图解密码技术(一)密码
第一章 环游密码世界
1.3 对称密码和公钥密码
1.3.1 密码算法
加密、解密的算法合在一起称为密码算法
1.3.3 对称密码与公钥密码
- 对称密码:加密和解密时使用同一个秘钥
- 公钥密码:也是非对称密码,加密和解密时使用不同的秘钥
1.3.4 混合密码
将对称密码和公钥密码结合起来的密码方式称为混合密码。
1.4 其它密码技术
1.4.1 单向散列技术
为了防止软件被篡改,软件发布者会在发布软件的同时发布该软件的散列值。散列值就是用单向散列函数计算出来的数值。使用者可以自行计算下载软件的散列值冰并和软件发布者公布的散列值进行对比,如果两个散列值相同,说明下载的文件与发布者发布的文件是一致的。
单向散列函数保证的并不是机密性,而是完整性。
1.4.2 消息认证码
使用消息认证码,不但能够确认消息是否被篡改,而且能够确认消息是否来自所期待的通信对象。
消息认证码不仅可以保证完整性,而且还提供了认证机制。
1.4.3 数字签名
Bob收到了Alice的邮件,内容是 “以100万元的价格购买该商品”。那么Bob怎么确认该邮件确实是Alice发的呢(邮件的发送者很容易被伪造)?Bob怎么确认邮件内容是否被篡改了呢?Alice确实发了该邮件,但后来Alice不想买了,所以谎称 “没有发送过该邮件”(这种事后推翻自己先前主张的行为成为否认)。Bob怎么阻止否认这种行为呢?
数字签名能够防止上述伪装,篡改,否认等行为。
数字签名是一种能够确认完整性,提供认证,并防止否认的密码技术。
1.4.4 伪随机数生成器
随机数承担着秘钥生成的重要职责,例如在SSL/TLS通信时,会生成一个仅用于当前通信的临时秘钥(会话秘钥),这个秘钥就是基于伪随机数生成器生成的。
1.4.5 总结:威胁与应对这些威胁的密码技术
第三章 对称密码
3.3 从文字密码到比特序列密码
3.3.1 编码
将现实世界中的东西映射为比特序列的操作称为编码。
比如上图中采用的就是ASCII编码。
3.3.2 XOR
如果选择一个合适的随机比特序列B,仅仅使用异或就可以实现一个高强度的密码。
3.4 一次性密码本–绝对不会被破译的密码
原理:将明文与一串随机的比特序列进行XOR运算。
3.4.4 一次性密码本为何无法破译
一次性密码本无法破译的根源在于 无法确认破译后的字符串是否是正确的明文。
假设对 username
这个字符串进行XOR加密,那么在破译时,需要尝试所有的秘钥,那么
破译时,既会出现 username
这个正确的字符串,也会出现比如 aaaaaaaa
,bbbbbbbb
这样的规则字符串,也会出现 password
这样有意义的英文单词,也就是说破译后会出现明文中所有可能的字符组合,从中无法判断哪个才是正确的。
3.5 DES(Data Encryption Standard)
现在 DES 已经能够被暴力破解。
3.5.2 加密和解密
DES是一种将64比特的明文加密成64比特密文的对称密码算法。DES的秘钥长度是64比特,其中每隔7比特会设置一个用于错误检查的比特,因此实际上密码长度是56比特。
DES以64比特的明文为一个单位进行加密,这个64比特的单位称为分组,以分组为单位进行处理的密码算法称为 分组密码。
DES每次只能加密64比特的数据,如果要加密的明文较长,就需要对DES加密进行迭代,迭代的具体方式称为 模式。
3.5.3 DES的结构(Feistel 网络)
加密
在 Feistel 网络中,加密的各个步骤称为 轮,整个加密的过程就是进行若干次轮的循环。DES是一种16轮循环的 Feistel 网络。
下图中就是 Feistel 网络中一轮的计算流程:
子密钥指的是本轮加密使用的密钥,在 Feistel 网络中,每一轮都需要使用一个不同的子密钥。
一轮的具体步骤如下:
- 将输入的数据等分为左右2侧
- 将输入的右侧直接发送到输出的右侧
- 将输入的右侧发送到轮函数
- 轮函数根据右侧数据和子密钥计算出一串看上去是随机的比特序列
- 将步骤4中得到的比特序列与左侧数据进行XOR运算,并将结果作为加密后的左侧
从这个过程中可以发现,一轮后右侧的数据没有加密,因此在每轮之间需要将左侧和右侧的数据对调。
如下展示了一个三层的 Feistel 网络:
解密
我们尝试将一轮加密的输出结果用相同的子密钥重新运行一次,无论轮函数具体是什么,都能够将密文还原为明文。
有多轮的情况也一样,解密时只要按照相反的顺序来使用子密钥就可以了。
Feistel 网络的特点:
- 轮数可以任意增加
- 可以使用任意复杂的轮函数
- 加密和解密可以用完全相同的结构
在AES候选的5个算法中,有3个算法(MAR6,RC6,Twofish)都是使用了 Feistel 网络。
3.6 三重DES
3.6.1 什么是三重DES
三重DES是为了增加DES强度,将DES重复三次得到的一种密码算法
3.6.2 三重DES的加密
明文经过三重DES处理才能变成最后的密文,DES秘钥的长度实际上是56比特,因此三重DES的秘钥长度就是168比特。
三重DES的过程为什么是:加密 -> 解密 -> 加密 呢?这是为了兼容普通的DES加密,如果三重的秘钥都相同,那么三重DES也就等同于普通DES了。
3.7 AES的选定过程
3.7.1 什么是AES
AES:Advanced Encryption Standard,是取代其前任标准(DES)而成为新标准的一种对称加密算法。
全世界提供了多个对称密码算法作为AES的候选,最终从这些候选中选出了一种名为 Rijndael 的对称加密算法。
3.8 Rijndael
Rijndael 也是分组密码。
3.8.2 Rijndael的加密解密
Rijndael 算法也是多轮的,但每一轮中,Rijndael使用了SPN结构。
加密
每一轮中的步骤大致如下:
解密
其中的 InvMixColumns, InvShiftRows, InvSubBytes 分别为 MixColumns, ShiftRows,SubBytes 的反向运算。
第四章 分组密码的模式–分组密码是如何迭代的
在第三章介绍的DES和AES都属于分组密码,它们只能加密固定长度的明文,如果需要加密任意长度的明文,就需要对分组密码进行迭代,而分组密码的迭代方式就称为分组密码的 模式。
4.2 分组密码的模式
4.2.1 分组密码与流密码
- 分组密码:每次只能处理特定长度的一块数据的一类密码算法,一个分组的比特数就称为分组长度。
- 流密码:对数据流进行连续处理的一类密码算法,流密码中一般以1比特,8比特或32比特为单位进行加密和解密。
4.2.2 什么是模式
分组密码的主要模式有以下5种:
- ECB模式:Electronic CodeBook Mode(电子密码本模式)
- CBC模式:Cipher Block Chaining mode(密码分组链接模式)
- CFB模式:Cipher FeedBack mode(密文反馈模式)
- OFB模式:Output FeedBack mode(输出反馈模式)
- CTR模式:CounTer mode(计数器模式)
4.2.3 明文分组与密文分组
- 明文分组:分组加密算法中作为加密对象的明文
- 密文分组:使用分组密码算法将明文分组加密之后所生成的密文
4.2.4 主动攻击者 Mallory
窃听者Eve只能被动地进行窃听,而主动攻击者则可以主动介入发送者和接收者之间的通信过程,进行阻碍通信或者篡改密文等活动。
4.3 ECB模式
将明文分组直接加密的方式就是ECB模式,这种模式非常简单,但是因为存在弱点因此一般不会使用。
4.3.1 什么是ECB模式
在ECB模式中,明文分组加密之后的结果将直接成为密文分组。
使用ECB模式时,相同的明文分组会被转化为相同的密文分组,也就是说,我们可以将其理解为一个巨大的 明文分组 -> 密文分组 的对应表,因此ECB模式被称为电子密码本模式。
当最后一个明文分组的长度小于分组长度时,需要用一些特定的数据进行填充。
4.3.3 对ECB模式的攻击
假设攻击者Mallory能够改变密文分组的顺序,当接收者对密文进行解密时,由于密文分组顺序被改变,相应的明文分组顺序也会被改变,即Mallory无需破译密码即可操纵明文。
假设分组长度为128比特,某银行的转账请求数据由以下3个分组构成:
- 分组1:付款人的银行账号
- 分组2:收款人的银行账号
- 分组3:转账金额
我们可制作一个从 A-5374 账号 向 B-6671 账号转账1亿元的转账请求,用16进制数据表示如下:
加密后的密文对应如下:
Mallory只需将分组1和分组2的密文调换一下顺序,即可将转账请求篡改成 从 B-6671 账号向 A-5374 账号转账1亿元。
Mallory对密文进行的篡改,可以通过第8章介绍的消息认证码检测出来,不过如果使用其他模式,这种攻击从一开始就是不可能实现的。
4.4 CBC模式
4.4.1 什么是CBC模式
CBC模式是将前一个密文分组与当前明文分组的内容混合起来(XOR运算)进行加密。
4.4.2 初始化向量
当加密第一个明文分组时,因为不存在前一个密文分组,因此需要事先准备一个长度为分组长度的比特序列来代替,这个比特序列就是初始化向量。
4.4.4 对CBC模式的攻击
Mallory可以修改初始化向量的中某些比特位,这样就会造成解密后得到的明文分组1中的某些比特位翻转。
4.5 CFB模式
4.5.1 什么是CDB模式
在CFB模式中,前一个密文分组会被送回到密码算法的输入端。
4.5.5 对CFB模式的攻击
对CFB模式可以实施重放攻击。
假设第一天Bob向Alice发送了4个分组的密文,Mallory将这4个分组的密文保存起来,第二天Bob向Alice又发送了内容不同的4个密文分组。
Mallory将后3个密文分组替换为昨天发送的后3个密文分组。
这样Alice收到密文后,第一个分组可以正常解密,第二个分组解密失败,但是后2个密文分组同样可以解密成功。此时Alice没有办法分辨第2个分组出错到底是通信错误还是认为攻击。
要做出这样的判断,需要使用第8章介绍的消息认证码。
4.6 OFB模式
4.6.1 什么是OFB模式
OFB模式并不是通过密码算法对明文直接加密,而是通过将明文分组和密码算法的输出进行 XOR 运算来产生密文分组的。
4.6.3 OFB算法和CFB算法的比较
OFB算法和CFB算法的区别仅仅在于密码算法的输入:
- CFB模式中,密码算法的输入是前一个密文分组
- OFB模式中,密码算法的输入则是密码算法的前一个输出
4.7 CTR模式
CTR模式是一种将逐次累加的计数器进行加密来生成密钥流的流密码。
4.7.1 计数器的生成方法
每次加密时都会生成一个不同的值(nonce)来作为计数器的初始值,当分组长度为128比特时,计数器的初始值可能是像下面的形式:
其中前8个字节为nonce,这个值在每次加密时都是不同的,后8个字节为分组序号,这个部分会逐次累加,在加密过程中,计数器的值会产生以下变化:
4.8 应该使用哪种模式
第五章 公钥密码
5.3 密钥配送问题
5.3.1 什么是密钥配送问题
Alice给Bob发邮件时,不发送密钥,Bob无法解密,发送密钥,Eve也可以解密。
解决密钥配送问题的方法:
- 事先共享密钥
- 通过密钥分配中心
- 通过 Diffie-Hellman 密钥交换
- 通过公钥密码
5.3.3 密钥分配中心
- Alice向密钥分配中心发出想要和Bob通信的请求
- 密钥分配中心通过伪随机数生成器生成一个会话密钥,这个密钥是供Alice和Bob本次通信中临时使用的密钥
- 密钥分配中心从数据库中取出Alice和Bob的密钥
- 密钥分配中心用Alice的密钥加密会话密钥,发送给Alice;用Bob的密钥加密会话密钥,发送给Bob
- Alice用自己的密钥解密,得到会话密钥
- Alice用会话密钥加密邮件,发送给Bob
- Bob对来自分配中心的消息进行解密(用自己的密钥),得到会话密钥
- Bob用会话密钥对Alice的邮件进行解密
- Alice和Bob删除会话密钥
5.3.4 通过 Diffie-Hellman 密钥交换来解决密钥配送问题
这个在第11章中详述
5.3.5 公钥密码
发送者使用公钥密码进行加密,接收者使用私钥进行解密。
5.4 公钥密码
5.4.1 什么是公钥密码
公钥密码中,加密密钥一般是公开的,但是解密密钥一定不能公开。
5.4.3 公钥通信的流程
5.4.5 公钥密码无法解决的问题
在公钥通信中,我们需要判断所得到的公钥是否正确合法,这个问题被称为公钥认证问题。
5.6 RSA
5.6.1 什么是RSA
RSA可以被用于公钥密码和数字签名。
5.6.2 RSA加密
RSA加密可以用下面的公式来表达:
RSA的密文是对代表明文的数字的E次方求mod N的结果。
E和N是RSA加密的密钥,也就是说,E和N的组合就是公钥,一般写成公钥是(E, N)。
5.6.3 RSA解密
RSA的解密可以用下面的公式来表达:
这里使用的N和加密时用的N相等,D和N的组合就是私钥。
5.7 对RSA的攻击
5.7.4 中间人攻击
Mallory混入发送者和接收者中间,对发送者伪装成接收者,对接收者伪装成发送者。
Alice准备向Bob发送一封邮件:
- Alice向Bob索取公钥
- Mallory拦截了Bob的邮件,使其无法发送给Alice。Mallory把Bob的公钥保存起来,然后把自己伪装成Bob,把自己的公钥发给Alice
- Alice用收到的公钥(Mallory的公钥)加密邮件,发送给Bob
- Mallory拦截了邮件,用自己的私钥解密邮件。
- Mallory篡改邮件后,再用Bob的公钥进行加密,然后伪装成Alice,发送给Bob
- Bob接收到邮件解密后,就看到了Mallory篡改后的邮件,但是他以为是Alice发送的
要防御中间人攻击,还需要一种手段来确认收到的公钥是否真的来自Bob,这就是认证。
第六章 混合密码系统
混合密码系统用对称密码来加密明文,用公钥密码来加密对称密码中所使用的密钥。
混合密码系统解决了公钥密码速度慢的问题(因为相比消息的长度,密钥的长度较短),对称加密中的密钥配送问题。
网络上的密码通信所使用的 SSL/TLS 都运用了混合密码系统。
- 数字签名:由单向散列函数和公钥密码组合而成
- 证书:由公钥和数字签名组合而来
- 消息认证码:由单向散列函数和密钥组合而成
阿瓦达啃小瓜: 是在 openresty 中使用的吗?
hi,我来啦: require "resty.core"运行报错 C:\lua\luarocks\systree\share\lua\5.1\resty\core.lua:3: attempt to index global 'ngx' (a nil value) 咋解决啊
起起落落: 是不是说少了倒排索引?
ctotalk: thanks very good