DES
DES概述
DES(Data Encryption Standard)是一种对称密钥
的分组加密
算法.
DES使用同一个长为64位(实际只有56位)的密钥进行加密和解密.
其分组为64位(8个字节),如果加密的数据不是64位的倍数,则按照某种规则进行填充.
到目前为止,DES已经不是一种安全的加密方法,主要因为它使用的56位密钥过短,现在已经逐渐被AES
所取代.
DES算法将明文进行一系列的排列和替换来实现加密,关键过程为使用原始密钥来生成16个密钥,然后分别使用这16个密钥对数据依次进行一系列的位操作,一共进行16次,最终得到密文.解密相同,只不过反向(密钥使用顺序颠倒)进行操作.
DES加密流程
加密流程图(来自维基百科):
在核心加密之前需要执行一个密钥调度
,即根据原始密钥
生成16个48位的子密钥
用于后续操作.
开始加密之前,先对明文进行一次置换,其中IP
和FP
为一对互逆的置换,即FP为IP的反函数
.IP用于将明文Plaintext
先进行一次换位处理,打乱原来的顺序,得到一个乱序的明文组,然后再进行核心的加密.
将64位明文组分成2部分,各为32位,并被交叉地分别处理,这种交叉结构被称为费斯妥结构
,其保证了加密和解密过程足够相似,有利于电路/代码的实现.
接着就是F函数
,这个函数即为DES的核心,使用生成好的48位子密钥
对32位的数据进行操作,完成1次加密操作,一共有16次.
初始置换IP
IP根据一个IP置换表进行换位:
也就是说,原来的64位明文为M0,置换后的明文为M1,
将M0的第58位换到M1的第1位,M0的第50位换到M1的第2位……以此类推.
置换完成后,将M1前后分成2块L0
和R0
,各为32位.
密钥调度
密钥调度即子密钥的生成.
DES根据初始的64位密钥来生成16个不同的子密钥,原来64位中有56位是有效位,其余8位(根据PC-1置换表)被用于奇偶校验
,并最后被舍弃.
密钥调度流程图(来自维基百科):
PC-1置换选取56位块
首先将64位原始密钥使用PC-1置换表
进行换位,并分成2组,该表只指定了56位,剩下的第8,16,24,32,40,48,56,64位共8位被舍弃.
1 | // PC-1置换表,因为无图所以用代码表示了 |
这样就将64位原始密钥拆分成了2个28位的部分C0
和D0
.
生成16个块Ci,Di(i=1-16)
接下来根据公式
进行循环左旋
生成16个块Ci,Di(每个块都有一对Ci和Di)
其中左旋位数由r[]
指定,r[]
固定如下:
1 | // 第0位无意义 |
例如有
1 | C0:1111000011001100101010101111 |
生成16个子密钥K
然后根据公式
进行Ki(i=1->16)的生成,CnDn
代表将Cn和Dn连接在一起.
其中PC2代表使用PC-2置换表
进行换位,从CiDi
中选取48位作为最终的密钥Ki.
1 | // PC-2置换表,因为无图所以用代码表示了 |
最终生成的16个48位比特串(块)Ki(i=1-16)即为16个子密钥,用于后续的加密.
轮函数加密
流程仍然是这个图:
说白了就是在每一轮中将2块数据交替地进行F()处理
,然后将处理后的值与本轮中另一个块进行异或.
F函数
F函数将一个32bit的(半)块
进行一次E置换
,置换时进行了扩张
,生成48bit的块,然后与48位的子密钥K
进行异或
,得到的48bit的结果再分成8组,每组为6bit,经过S盒
,每组生成4bit的结果,组合起来一共为4*8==32bit的结果,然后再进行一次P置换
,即为F函数的最终结果.
最终的结果仍然为32bit,与输入的32bit块大小一样,准备用于下一步加密.
E置换
通过该表进行32bit -> 48bit的扩张.
异或
即将E置换
后的48位扩张结果与子密钥K进行异或.
S盒代换
将异或结果分成6bit一组,共8组.经过S盒后,6位变为4位.
S盒代换有8个盒子(S-Box),分别对应8个组,通过查找表进行代换.
图片来源于这篇文章:
每一组查找到的数转为4位二进制数即为输出的4bit结果.
P置换
P为固定置换,将经过S盒变换得到的32bit进行一个置换操作.
需要注意一点:这个P置换是精心设计的,使得这一轮同一个S盒输出的四个bit,在下一回合的扩张之后,交由四个不同的S盒去处理.
1 | // P置换表,因为无图所以用代码表示了 |
反函数置换FP
FP和IP为反函数关系,轮函数后再进行一次FP置换
得到最终结果.
IP逆
即为FP.
至此,即为整个加密,可以发现,使用同一个子密钥对一段数据进行两次轮函数(?)处理,得到的结果不变,这就体现出DES的加解密几乎一致.
DES解密
只需要将生成的16个子密钥逆转即可,即
1 | reverse_keys(SubKeys,16); // 自定义的函数,将16个子密钥反序 |