揭开分组密码的面纱

前面的几篇博文简单地介绍了传统加密的知识,大家应该已经了解了常见的传统加密方案以及代码实现。这篇文章主要来介绍密码学中的分组密码的工作模式以及填充模式,这篇文章没有相关的代码,都是一些简单的理论。这里说一下为什么是先介绍分组密码,这是因为分组密码的理论是DES,3DES,AES加密的基础理论之一,而且和加密解密算法的跨平台性有一定的关联。

分组密码

分组密码是将一个明文分组作为整体加密并且通常得到的是与明文等长的密文分组。典型的分组大小是64位或128位。常见的分组密码:DES、AES等。为什么需要对明文进行分组?这个很容易想明白,比如一个应用程序总共就只能获得3M的内存空间进行执行程序,而需要加密的文件是100M,这个时候就不得不进行文件拆解加密,当然分组的原因还有其他因素。既然我们需要对明文进行分组,那么采用什么姿势来分组呢?不废话,先给大家看一幅图,如下:

分组密码工作模式

工作模式

分组密码的输入为具有b位固定长度的明文分组和密钥,输出为b位的密文。明文长度若大于b位,则可简单将其分成b位一组的块。每次使用相同的密钥对多个分组加密,则会引发许多安全问题。为了将分组密码应用于各种各样的实际应用,NIST定义了5种“工作模式“。从本质上讲,工作模式是一项增强密码算法或者使算法适应具体应用的技术,例如将分组密码应用于数据块组成的序列或者数据流。这5种模式实际上该覆盖了大量使用分组密码的使用。这五种工作模式就是上图中的ECB 、CBC、CFB、OFB、CTR。

电码本模式-ECB

电码本(Electronic Code Book,ECB)模式,它一次处理一组明文分块,每次使用相同的密钥加密。使用电码本这个词是因为对于给定的密钥,任何b位的明文组只有唯一的密文与之对应,所以,可以想象存在一个很厚的密码本,根据任意b位明文都可以查到相应的密文。ECB模式特别适合于数据较少的情况,比如加密密钥。因此,若想安全传输一个DES或AES密钥,选择这种模式是合适的。ECB最重要的特征是一段消息中若有几个相同的明文组,那么密文也将出现几个相同的密文分组。对于很长的消息,ECB模型可能不安全。如果消息是非结构化的,密码分析者可能利用这些规律性特征来破译。

下面看一下电码本模式的原理图,如下:
这里写图片描述

上图中的明文由一串b位的块组成,记为P1,P2, …. ,Pn ,相应的密文分组依次是C1,C2,…,Cn。则ECB模式下的加密解密如下:

Cj=E(K,Pj)    Pj=D(K,Cj)    j=1,….,N

明文若长于b位,则可简单将其分成b位一组的块,有必要则可对最后一块进行填充。解密也是一次执行一块,且使用相同的密钥。

从上图中我们还可以看到,如果采用ECB工作模式可以并发地加密与解密,即各个分组模块独立地进行加密与解密,互不影响,最后在统一进行拼接工作。

密文分组链接模式-CBC

密文分组链接模式(Cipher Block Chaining,CBC):这种模式下加密算法的输入是当前的明文组和上一个密文组的异或,而使用的密钥是相同的。这就相当于将所有的明文组链接起来了。加密算法的每次输入与本明文组没有固定的关系。因此,若有重复的明文组,加密后就看不出来了。和ECB方式类似,CBC方式也要求如果最后的分组不是完整的分组,则需要填充至b位的满分组。解密时,每个密文分组分别进行解密,再与上一块密文异或就可恢复出明文。第一块明文可以和一个初始向量(IV)异或后再加密,以产生第一个明文分组。解密时将第一块密文解密的结果与IV异或而恢复出第一块明文。IV是和密文具有相同的长度的数据分组。IV必须为收发双方共享,但第三方不能预测。特别地,对于任意的给定明文,在IV产生之前,不能预测和本明文关联的IV。为了最大程度地安全,IV不能不经授权而修改。对IV先用ECB加密后再发送的方式可以实现这一
要求。CBC的链接机制使得它适合于加密长度大于b位的消息。

密文分组链接模式的原理图:

CBC模式可按如下定义:

我们可以明显地看到CBC模式的原理图要比ECB模式的复杂一点,而且相关“公式“也不一样,关键之处在于算法输入之前多了一步异或处理。加密时明文分组要与前一个分组的密文进行异或,然后再进行本分组的加密,解密时将解密算法的输出结果与前一个密文分组异或得到该分组的明文。很明显该工作模式不能并发的加密与解密,因为当前组依赖于前一分组。

密文反馈模式-CFB

密文反馈模式(Cipher Feedback,CFB):密文反馈模式和下面要说的输出反馈模式以及计数器模式,亦可将分组密码当做流密码使用。流密码不需要将明文填充到长度是分组长度的整数倍,且可以实时操作。所以,待发送的字符流中任何一个字符都可以用面向字符的流密码加密后立即发送。密文反馈模式可以说是把分组的长度更颗粒化,即分组之后再分组,比如之前是分组长度为b位,但是在加密时每次传输s位的数据进行加密(s < b)。尽管CFB可以被视为流密码,但是它和流密码的典型构造并不一致。典型的流密码输入某个初始值和密钥,输出位流,这个位流再和明文位进行异或运算。而CFB模式里,与明文异或的位流是与明文相关的。

密文反馈模式的原理图:
这里写图片描述

CFB模式可按如下定义:
这里写图片描述
上图描述了CFB模式。假设传输单元时s位,s通常为8。同使用CBC模式一样,明文的各个单元要链接起来,所以任意个明文单元的密文都是前面所有明文的函数。在这种情况下,明文被分成s位的片段而不是b位的单元。

首先来考虑加密。加密函数的输入是b位的移位寄存器,它的值为初始向量IV。加密函数输出最左边的s位与明文的第一个分段P1异或得到密文的第一个单元C1,然后将C1发送出去,接着,移位寄存器左移s位,C1填入移位寄存器的最右边s位。就这样,直到所有明文单元被加密完。解密使用相同的办法,只是有一点不同:将收到的密文单元与加密函数的输出异或得到明文单元。

输出反馈模式-OFB

输出反馈模式(Output FeedBack,OFB) :输出反馈模式的结构和CFB很相似,它用加密函数的输出填充移位寄存器,而CFB是用密文单元来填充移位寄存器。其他的不同是,OFB模式对整个明文和密文分组进行运算,而不是仅对s位的子集运算。

输出反馈模式的原理图:

输出反馈模式可按如下定义:

令分组的长度为b。如果明文的最后一个分组包含u位(用*指示),u < b,那么最后的输出分组ON的的最左边的u位用来做异或运算。最后的输出分组的其余b-u位丢弃不用。

如同CBC和CFB一样,OFB模式需要一个初始化向量。在OFB模式时,IV必须是一个时变值,即IV对每次加密运算都是唯一的。原因是加密输出的分组构成的序列Oi仅仅依赖于密钥和IV,而不依赖于明文。因此,对于给定的密钥和IV,用于和明文流进行异或运算的输出位流是固定的。如果两个不同的消息在相同的地方有一个相同的明文分组,那么攻击者就能够判断出那部分的Oj输出流。

OFB的一个优点是传输过程中在某位上发生的错误不会影响其他位。
OFB的缺点是抗消息流篡改攻击的能力不如CFB。
OFB具有典型流密码的结构,因为密码产生的位流是初始值和密钥的函数,且产生出的位流和明文进行了异或。产生的位流本身是和明文独立的。OFB模式与流密码的差别是OFB一次加密一个明文分组,分组的典型长度是64位或128位。许多流密码一次加密一个字节。

计数器模式-CTR

计数器模式(Counter,CTR):计数器使用与明文分组规模相同的长度,这里要求加密不同的明文组计数器对应的值必须是不同的。典型地,计数器首先被初始化为某一值,然后随着消息块的增加计数器的值加1。加密时,计数器加密后与明文分组异或得到密文分组;没有链接。解密使用具有相同值的计数器序列,用加密后的计数器的值与密文分组异或来恢复明文分组。因此,解密时必须知道初始计数器的值。

计数器模式的原理图:
这里写图片描述

计数器模式可按如下定义:
这里写图片描述

在上图中的Counter如同OFB模式一样,初始计数器的值必须为时变值;也就是说,使用相同密钥加密的所有消息必须各自具有不同的T1.而且,所有消息的所有Ti值也必须唯一。保证计数器值唯一的一个办法是每一个消息计数器都增加1.即每个消息的第一个计数器的值都要比前一条消息的最后一个计数器的值多1.

填充模式

一般情况下,使用不同语言开发的双方只有约定加密模式和明文填充方式,保证字节序列相同,保证密钥的生成方式与编码相同,使用相同字符编解码方式等,才可以保证加解密双方的互通。由于不同平台和不同编程语言遵循的加密模式具有一致的定义,因此只要加解密双方按照协商指定模式进行加解密即可。而对数据在加密时进行填充、解密时去除填充则是通信双方需要重点考虑的因素。对原文进行填充,主要是基于以下原因:首先,考虑安全性。由于对原始数据进行了填充,使原文能够“伪装”在填充后的数据中,使得攻击者很难找到真正的原文位置。其次,由于块加密算法要求原文数据长度为固定块大小的整数倍,如果加密原文不满足这个条件,则需要在加密前填充原文数据至固定块大小的整数倍。另外,填充也为发送方与接收方提供了一种标准的形式以约束加密原文的大小。只有加解密双方知道填充方式,才可知道如何准确移去填充的数据并进行解密。

常用的填充方式至少有5种,不同编程语言实现加解密时用到的填充多数来自于这些方式或它们的变种方式。

1.填充数据为填充字节序列的长度

这种填充方式中,填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。假定块长度为8,原文数据长度为9,则填充字节数
等于0x07;如果明文数据长度为8的整数倍,则填充字节数为0x08。填充字符串如下:
原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 08 08 08 08 08 08 08 08

2.填充数据为0x80后加0x00

这种填充方式中,填充字符串的第一个字节数是0x80,后面的每个字节是0x00。假定块长度为8,原文数据长度为9或者为8的整数倍,则
填充字符串如下:
原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00 00

3.填充数据的最后一个字节为填充字节序列的长度

这种填充方式中,填充字符串的最后一个字节为该序列的长度,而前面的字节可以是0x00,也可以是随机的字节序列。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07或FF FF FF FF FF FF FF FF FF 0A B0 0C 08 05 09 07
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 08或FF FF FF FF FF FF FF FF 80 06 AB EA 03 02 01 08

4.填充数据为空格

这种填充方式中,填充字符串的每个字节为空格对应的字节数0x20。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:

原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 20 20 20 20 20 20 20
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 20 20 20 20 20 20 20 20

5.填充数据为0x00

这种填充方式中,填充字符串的每个字节为0x00。假定块长度为8,原文数据长度为9或者8的整数倍,则填充字符串如下:
原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00

总结

本篇文章简单地阐述了分明密码的工作模式与填充模式,让大家对分组密码有个简单的认识,顺便自己回顾一下这个知识点,通过对这个知识点的研究,我终于想明白两年多前还在上家公司遇到的不同平台不同语言使用同一个加密算法不能相互解密加密的原因,真的是有可能是因为当时的工作模式选取不同填充方式选择不同而造成的。以后再遇到类似问题就可以一层一层的剥离定位。工作之后,对于理论的补充也是相当的重要。后面还会陆续总结这方面的内容,喜欢的同学可以关注一下专栏可以第一时间收到通知。

参考资料

《密码编码学与网络安全》第六版
《关于加密数据的填充方式的研究》

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值