一次性密码本
一次性密码本是一种非常简单,它的原理是“将明文与一串随机的比特序列进行XOR运算”。如果将硬币的证明设为0,反面设为1,则通过不断掷硬币就能产生这样一串随机的比特序列。
加密
解密
正如上面所讲到的那样,一次性密码本是一种非常简单的密码,如此简单的密码居然无法破译,这真是让人匪夷所思。这里说的无法破译,并不是指在现实的时间内难以破译,而是指即便拥有一种运算能力无穷大的计算机,可以在一瞬间遍历任意大小的密钥空间,也依然无法破解。
我们假设对一次性密码本的密文进行尝试进行暴力破解,那么总有一天我们会尝试到和加密时相同的密钥,也就能解密出明文midnight,这是毋庸置疑的事实,然而,即便我们解密出midnight这个字符串,我们也无法判断它是否是正确的明文。
这是因为在对一次性密码本尝试解密的过程中,所有的64比特的排列组合都会出现,这其中包含像aaaaaaaa,ZZZZZZZZ这样的规则字符串,也会包含midnight,onenight等英文单词,还会包含其他看不懂的组合,所以,我们无法判断出其中哪一个才是正确的明文。
所谓玻璃破解,就是按顺序将所有的密钥都尝试一遍,并判断得到的是不是正确的明文的方法。然后在一次性密码本中,由于我们无法判断得到明文是不是正确的明文,因此一次性密码本是无法破译的。
为什么没有被普遍使用
密钥配送
最大的问题在于密钥的配送。
我们来设想一下使用一次性密码本进行通信的场景,发送者Alice使用一次性密码本生成密文发送出去。发送的密文即便被窃听者Eve截获也没关系,因为一次性密码本是绝对无法破译的。
接收者Bob收到了Alice发来的密文。Bob要想进行节目,就必须使用和Alice进行加密时相同的密钥,因此Alice必须将密钥发送给Bob,且该密钥的长度和密文是相等的。但这样就产生了一个矛盾,如果能够有一种方法将密钥安全送出去,那么岂不是也可以用同样的方法来安全地发送明文了么?
密钥保存
一次性密文本中,密钥的长度必须和明文的长度相等,而且由于密钥保护着明文的机密性,因此必须妥善保存,不能被窃听者窃取。不过,如果能够有办法安全保护与明文一样长的密钥,那岂不是就有办法安全保存明文本身了么?
密钥的重用
在一次性密码本中绝对补鞥呢用重用过去用过的随机比特序列,一次性密码本中的“一次性”由此而来。这是因为作为密钥的比特序列一旦泄露,过去所有的机密通信内容将全部被解密。
密钥的同步
一次性密码本中还会产生发送者与接收者之间的密钥同步问题。当明文很长时,一次性密码本的密钥也会跟着变长。如果明文是一个大小为100MB的文件,则密钥的大小也一定是100MB。而且在通信过程中,发送者和接收者的密钥的比特序列不允许有任何错位,否则错位后的所有信息都无法解密。
密钥的生成
一次性密码本中,需要生成大量的随机数。这里的随机数并不是通过计算机程序生成的伪随机数,而必须是无重现性的真正随机数。
综上所述,一次性密码本是一种几乎没有实用的密码。但是,一次性密码本的思路却孕育出了流密码 。流密码使用的不是真正的随机比特序列,而是伪随机数生成器产生的比特序列。流密码虽然不是无法破译的,但只要使用高性能的伪随机数生成器,就能够构建出较高强度的密码系统,后续会继续介绍。
DES
DES的密文可以在短时间内被破译,因此除了用它来解密一起的密文以外,现在我们不应该再使用DES了。
加密和解密
DES是一种将64比特的明文加密成64比特的密文的对称密码算法,它的密钥的长度是56比特。尽管从规格上来说,DES的密钥长度是64比特,但由于每隔7比特会设置一个用于错误检查的比特,因此实质上其密钥长度是56比特。
DES 是以64比特的明文(比特序列)为一个单位来进行加密的,这个64比特的单位称为分组 ,一般来说,以分组为单位进行处理的密码算法称为分组密码,DES就是分组密码的一种。
DES每次只能加密64比特的数据,如果要加密的明文比较长,就需要对DES加密进行迭代(反复),而迭代的具体方式就称为模式。
DES的结构(Feistel网络)
DES的基本结构是由Horst Feistel设计的,因此也称为Feistel网络(Feistel network)、Feistel结构(Feistel structure)或者Feistel密码(Feistel cipher)。这一结构不仅被用于DES,在其他很多密码算法中也有应用。
Feistel网络中,加密的各个步骤称为轮,整个加密过程就是进行若干次轮的循环,下图,展现的是Feistel网络中一轮的计算流程。DES是一种16轮循环的Feistel网络。
上图两个方框表示Feistel网络中的一轮的输入(明文)。输入的数据被等分为左右两半分别进行处理。在图中,左半部分写作“左侧”,右半部分写作“右侧”。
下图的两个方框表示本轮的输出(密文)。输出的左半部分写作“加密后的左侧”,右半部分写作“右侧”。
中间的“子密钥”指的是本轮加密所使用的的密钥,在Feistel网络中,每一轮都需要使用一个不同的子密钥。由于密钥只在一轮中使用,它只是一个局部的密钥,因此才称为子密钥(subkey)。
轮函数的作用是根据“右侧”和子密钥生成对“左侧”进行加密的比特序列,它是密码系统核心。将轮函数的输出与“左侧”进行XOR运算,其结果就是“加密后的左侧”。也就是说,我们用XOR将轮函数的输出与“左侧”进行合并。而输入的“右侧”则会直接成为输出的“右侧”。
总结一下,一轮的具体计算步骤如下:
- 将输入的数据等分为左右两个部分
- 将输入的右侧直接发送到输出的右侧
- 将输入的右侧发送到轮函数
- 轮函数根据右侧数据和子密钥,计算出一串看上去是随机的比特序列
- 将上一步得到的比特序列与左侧序列进行XOR运算,并将结果作为加密后的左侧。
但是,这样看来,“右侧”根本没有加密,因此我们需要用不同的子密钥对一轮的处理重复若干次,并在没两轮处理指间将左侧和有责的数据对调。
上图展现了一个3轮的Feistel网络,3轮加密计算需要进行两次左右对调。对调只在两轮指间进行,租后一轮结束不需要对调。
那么,Feistel网络如何解密呢?
如上图所示,通过上述操作都能够将密文正确的还原明文。
有多轮的情况也是一样的,也就是说,Feistel网络的解密操作,只要按照相反的顺序来使用子密钥就可以完成了,而Feistel网络本身的结构,在加密和解密都是完全相同的。
Feistel网络性质
- Feistel网络,轮数可以任意增加。无论运行多少轮的加密计算,都不会发生无法解密的情况
- Feistel网络,加密时无论使用任何函数作为轮函数都可以正确解密。
- Feistel网络,加密和解密可以用完全相同的结构来实现,这也是Feistel网络的一个特点。
三重DES
现在DES已经可以在现实的时间内被暴力破解,因此我们需要一种替代DES的分组密码,三重DES就是出于这个目的被开发出来的。
三重DES是为了增加DES的强度,将DES重复3次所得到的一种密码算法,也称为TDEA(Triple Date Encryption Algorithm),通常缩写为3DES。
三重DES的加密
明文经过三次DES处理才能变成最后的密文,由于DES密钥的长度实质上是56比特,因此三重DES密钥的长度就是168比特。
三重DES并不是进行三次DES加密,而是加密->解密->加密的过程。在加密算法中加入解密操作,让人感觉很不可思议实际上,这个算法是IBM公司设计出来的,目的是为了让三重DES能够兼容普通的DES。
三重DES的解密
三重DES的解密过程和加密过程正好相反,是以密钥3,密钥2,密钥1的顺序执行解密->加密->解密的操作。
AES
AES(Advanced Encryption Standard)是取代前任标准DES而成为新标准的一种对称密码算法。全世界的企业和密码学家提交了多个对称密码算法作为AES候选,最终在2000年的时候,从这些候选算法中选出了有一种名为Rijndael的对称密码算法,并将其确定为AES。
Rijndael
Rijndael是由比利时密码学家Joan Daemen 和Vincent Rijmen设计分组密码算法,于2000年被选为新一代的标准算法密码-AES。
Rijindael的分组长度和密钥长度可以分别为32比特为单位,在128比特到256比特的范围内进行选择。不过AES规格中,分组长度固定为128比特,密钥长度只有128、192和256比特三种。
Rijndael加密和解密
和DES一样,Rijndael算法也是由多个轮构成,其中每一个轮分为SubBytes、ShiftRows、MixColumns和AddRoundKey共4个步骤。DES使用Feistel网络作为基本结构,而Rijndael没有使用Feistel网路,而是使用了SPN网路。
Rijndael的输入分组128比特,也就是16个字节。首先,需要逐个字节地对16字节地输入数据进行SubBytes处理。所谓SubBytes,就是以每个字节地值(0~255的任意值)为索引,从一张表拥有256个值替换表(S-Box)中查找出对应的值来处理。也就是说,要将一个1字节地值替换成另一个1字节地值。这个步骤用语言来描述比较麻烦,大家可以将它想象成为前面介绍的简单替换密码的256个字母的版本。
SubBytes之后需要进行ShiftRows处理。这一步是将以4字节为单位的行,按照一定的规则向左平移,且每一行平移的字节数是不同的。
ShiftRows之后需要进行MixColumns处理。这一步是对一个4字节地值进行比特运算,将其变为另外一个4个字节值。
最后,需要将MixColumns的输出与轮密钥进行XOR,即进行AddRoundKey处理。到这里Rijndael的一轮就接收了。实际上,在Rijndael中需要重复进行10~14轮计算。
通过上面的结构,我们可以发现输入比特在一轮中都会被加密。和每一轮都只加密一般输入的比特的Feistel网络相比,这种方式的优势在于加密所需要的轮数更少。此外,这种方式还有一个优势,即SubBytes、ShiftRows、MixColumns可以分别以字节、行、列为单位进行并行计算。
在加密过程中,每一轮所进行的处理为:
SubBytes——>ShiftRows——>MixColumns——>AddRoundKey
而在解密时,则是相反的顺序来进行的,即
AddRoundKey——>MixColumns——>ShiftRows——>SubBytes
其中,AddRoundKey是与轮密钥进行XOR运算,因此这一步在加密和解密是是完全相同的。
Rijndael的破译
对于Rijndael来说,可能会出现以前不存在的新的攻击方式。Rijndael的算法背后有这严谨的数学结构,也就是说从明文到密文的计算过程可以全部用公司来表达,这是在以前任何密码算法都不具备的性质。如果Rijndael的公司能够通过数学运算求解,哪也就是意味着Rijndael能够通过数学方法进行POI,而这也就为新的攻击方式的产生提供了可能。
补充
AES相比同类对称加密算法速度算是非常快,比如在有AES-NI的x86服务器至少能达到几百M/s的速度。安全性在可预见的未来是基本等同的,因为即使是128位也足够复杂无法被暴力破解。现在112位密码还在商业应用,而128位是112位的几万倍,所以在实务中用128位比较划算(稍节约资源)。
AES256比128大概需要多花40%的时间,用于多出的4轮round key生成以及对应的SPN操作。另外,产生256-bit的密钥可能也需要比128位密钥多些开销,不过这部分开销应该可以忽略。安全程度自然是256比128安全,因为目前除了暴力破解,并没有十分有效的代数攻击方法。
AES128和AES256主要区别是密钥长度不同(分别是128bits,256bits)、加密处理轮数不同(分别是10轮,14轮),后者强度高于前者。当前AES是较为安全的公认的对称加密算法。
关于用AES128还是AES256算法,个人认为AES128已经足够用,当然AES256可以作为一个营销手段使用。
应该使用哪种对称密码呢
首先,DES不应再应用任何新的用途。其次,我们也没有理由将三重DES用于任何新的用途。一般来说,我们不应该使用任何自制的密码算法,而是应该使用AES。因为其在选定的过程中,经过了全世界密码学家所进行的高品质的验证工作,而对于自制的密码算法则很难进行这样的验证。
参考资料
该系列的主要内容来自《图解密码技术第三版》