对称加密算法:Data Encryption Standard

所谓对称加密算法,指的是加密和解密使用相同密钥的加密算法,而 Data Encryption Standard (数据加密标准),简称 DES,就是一种经典的对称加密算法。

DES 设计遵循 “香农准则”:

  • 充分混乱:密钥、明文以及密文之间的依赖关系相当复杂。
  • 充分扩散:密钥的每一位数字影响密文的许多位数字,明文的每一位数字也应影响密文的许多位数字。

DES 具有以下属性:

  • 明文:M = { m1, m2, …, m64},64bits 信息。
  • 密文:C = { c1, c2, …, c64},64bits 信息。
  • 密钥:K = { k1, k2, …, k64},64bits,8为奇偶校验位,有效位 56 bits。

作为一个经典的加密算法,DES 在数十年经久不衰,本文则希望通过自顶向下的方法,探讨一下 DES 算法的具体原理。

另附:实现代码


一、DES 流程概览

在 DES 算法中,明文会被分组成 64 位一组。而每一组依次进入算法加密,因此在此我们只讨论 64位一组的加密。


1.1 总流程图

忽略一部分细节,DES 整个流程可用下图表示:

des-overall

这个图只是 DES 算法的大体过程,忽略了很大一部分技术细节,那些省略的细节也会在第二、三部分进行详细讲解。现在看不懂这个图也没有关系,后文将逐渐展开。看完第一部分,请回到这里,看看能否对 DES 算法过程有一个宏观认识。


1.2 IP 置换 (初始置换)

s1. 明文为 64bits 的信息,按下表所示进行重新排列,即新的第 1 位为原来的第 58 位,新的第 2 位为原来的第 50 位……原有信息被打乱,这个过程称之为 IP 置换

IP 置换表

58 50 42 34 26 18 10 2
60 52 44 36 28 20 12 4
62 54 46 38 30 22 14 6
64 56 48 40 32 24 16 8
57 49 41 33 25 17 9 1
59 51 43 35 27 19 11 3
61 53 45 37 29 21 13 5
63 55 47 39 31 23 15 7

s2. 将经过 IP 置换重排后的信息分割成左右两部分 L[0] (32bits),R[0] (32bits)。


1.3 Feistel 迭代

IP 置换后的 L[0], L[1] 以及 64bits 的密钥 k 作为 Feistel 函数的输入,经过 16 次相同迭代,输出 L[16] (32bits)R[16] (32bits)

注:这部分细节将会在后续进行讲解


1.4 IP 逆置换

将经过 Feistel 迭代的左右子串 L16,R16 按照 先右后左的 { R[16], L[16] } 顺序排列,经过 IP 置换的逆关系 IP逆 进行置换混淆,产生最后输出的密文。

IP 逆置换

40 8 48 16 56 24 64 32
39 7 47 15 55 23 63 31
38 6 46 14 54 22 62 30
37 5 45 13 53 21 61 29
36 4 44 12 52 20 60 28
35 3 43 11 51 19 59 27
34 2 42 10 50 18 58 26
33 1 41 9 49 17 57 25

上面这三步就是整个 DES 算法的大体步骤。不过也正如同前面所说,这里省略了大量步骤,其中一个关键的步骤就是被一笔带过的 Feistel 迭代,下面也将会从这里开始讲起。


二、Feistel 轮函数详解

2.1 初始置换后的 16 次迭代

在 IP 置换(初始置换)后,经过重新排列混淆的 64bits 信息被分为左右两部分: L0(32bits), R0(32bits),这时候,它们要经过 16 次迭代,具体迭代过程如下图:

  • L[i]: 直接为上一层的 R[i - 1]

  • R[i]: 略微复杂一些,它是上一层的 L[i - 1] 与 Feistel 函数返回值的异或。

  • Feistel 函数: 接受两个参数:R[i - 1] 和 k[i] (后面详解),返回一个 32bits 的值。


2.2 Feistel 函数

  • 参数:R[i - 1]: 32bits, k[i]: 48bits

  • 返回:32bits


2.2.1 Feistel: 总流程

s1. 32bits 的 R[i - 1] 通过 E 扩展,变为 48bits 的 E(R[i - 1])。

s2. E(R[i - 1]) xor k[i],结果为 48bits。

s3. 将上述 xor 操作得到的结果分为 8 份,每份就是 6bits。

s4. 让第 i 份通过 S(i)Box,将会从 6bits -> 4bits。

s5. 将 8 份 4bits 数据组合成 32bits 的数据。

s6. 将上一步得到的 32bits 数据经过 P置换,然后输出 32bits 数据。

如下图:


2.2.2 Feistel: E 扩展

Feistel 函数的一个步骤是:将 32bits 的 R[i - 1] 扩展成 48bits 的 E(R[i - 1]),这个过程不难理解。

首先,将 32bits 的 R[i - 1] 转化为 8 * 4 的矩阵。

现在,我们要扩展这个矩阵,使其扩展成 8 * 6 的矩阵,在首尾各增加一列

利用原矩阵数据,依次循环向后扩展。


2.2.3 Feistel: S-Box

DES的核心是 S-Box,除此之外的计算是线性的。S-Box 作为该密码体制的非线性组件对安全性至关重要,但 S-Box 的设计原理至今未公布,是否存在隐藏陷门 ( Hidden Trapdoors ) 不得而知。

S-Box 的设计准则

  • S-Box 中的每一行是整数 0-15 的一个置换
  • S-Box 不是它输入变量的线性或仿射函数
  • S-Box 的输入端每改变1位至少要引起输出端改变 2 位
  • S(X) 和 S(X + 001100) 至少有 2 位不同
  • 对 6 位二进制串 X = x1x2x3x4x5x6,S(X) != S(X + {11x5x600})
  • S-Box 的输入端保持任 1 位不变,则其它输入位的变化输出数字中 0 和 1 的总数近于相等。

S-Box 计算

设S[i] 的6位输入为 { b1 b2 b3 b4 b5 b6 }

  • 行号:r = ( b1 b6 )10

  • 列号:c = ( b2 b3 b4 b5 )10

  • 输出:(S[i])[r, c] 元素的值的二进制形式即为所要的 S[i] 的输出。

S1-Box 为例:

14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7
0 15 7 4 14 2 13 1 10 6 12 11 9 5 3 8
4 1 14 8 13 6 2 11 15 12 9 7 3 10 5 0
15 12 8 2 4 9 1 7 5 11 3 14 10 0 6 13
  • 输入:{ b1 b2 b3 b4 b5 b6 } = 101100

  • 行号:( b1 b6 )10 = (10)10 = 2

  • 列号:( b2 b3 b4 b5 )10 = (0110)10 = 6

  • 输出: S1[2, 6] = 2 = 0010


2.2.3 Feistel: P 置换

8 个 S-Box 最终会输出 8 组 4bits 的数据,将其合并为 32 bits,然后进行 P 置换,最后输出并参与 16 轮迭代。

P 置换表

16 7 20 21
29 12 28 17
1 15 23 26
5 18 31 10
2 8 24 14
32 27 3 9
19 13 30 6
22 11 4 25

三、子密钥 k[i] 生成

在上述 Feistle 函数中,另一个参数就是 48bits 的 k[i],而 k[i] 便是通过密钥 k 生成的。这部分的生成只与密钥 k 相关,不依赖明文密文,所以这一步完全可以在整个算法第一步完成。

用下图表示子密钥 k[i] 生成过程:


3.1 PC-1 置换

对 k 56bits 的非校验位进行 PC-1 置换混淆,得到左右各 28bits 两部分,记为 C[0], D[0]。

PC-1 置换表

57 49 41 33 25 17 9
1 58 50 42 34 26 18
10 2 59 51 43 35 27
19 11 3 60 52 44 36
63 55 47 39 31 23 15
7 62 54 46 38 30 22
14 6 61 53 45 37 29
21 13 5 28 20 12 4

3.2 循环左移

从 i 开始,利用 C[i - 1], D[i - 1],计算 C[i], D[i]

  • C[i] = LS[i] (C[i - 1]) 和D[i] = LS[i] (D[i - 1])
  • i = 1, 2, 9, 16 时:LS[i] (A) 表示 A 循环左移 1bit。
  • i = others 时:LS[i] (A) 表示 A 循环左移 2bits。

可以用下表表示:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1

3.3 PC-2 压缩置换

每一次循环,都拼接 C[i]D[i] 为 56bits 信息,进行 PC-2 压缩置换,压缩为 48bits,生成 k[i] 并输出。

PC-2 压缩置换表

14 17 11 24 1 5
3 28 15 6 21 10
23 19 12 4 26 8
16 7 27 20 13 2
41 52 31 37 47 55
30 40 51 45 33 48
44 49 39 56 34 53
46 42 50 36 29 32

附:全部 S-Box

S1:

14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7
0 15 7 4 14 2 13 1 10 6 12 11 9 5 3 8
4 1 14 8 13 6 2 11 15 12 9 7 3 10 5 0
15 12 8 2 4 9 1 7 5 11 3 14 10 0 6 13

S2:

15 1 8 14 6 11 3 4 9 7 2 13 12 0 5 10
3 13 4 7 15 2 8 14 12 0 1 10 6 9 11 5
0 14 7 11 10 4 13 1 5 8 12 6 9 3 2 15
13 8 10 1 3 15 4 2 11 6 7 12 0 5 14 9

S3:

10 0 9 14 6 3 15 5 1 13 12 7 11 4 2 8
13 7 0 9 3 4 6 10 2 8 5 14 12 11 15 1
13 6 4 9 8 15 3 0 11 1 2 12 5 10 14 7
1 10 13 0 6 9 8 7 4 15 14 3 11 5 2 12

S4:

7 13 14 3 0 6 9 10 1 2 8 5 11 12 4 15
13 8 11 5 6 15 0 3 4 7 2 12 1 10 14 9
0 6 9 0 12 11 7 13 15 1 3 14 5 2 8 4
3 15 0 6 10 1 13 8 9 4 5 11 12 7 2 14

S5:

2 12 4 1 7 10 11 6 8 5 3 15 13 0 14 9
14 11 2 12 4 7 13 1 5 0 15 10 3 9 8 6
4 2 1 11 10 13 7 8 15 9 12 5 6 3 0 14
11 8 12 7 1 14 2 13 6 15 0 9 10 4 5 3

S6:

12 1 10 15 9 2 6 8 0 13 3 4 14 7 5 11
10 15 4 2 7 12 9 5 6 1 13 14 0 11 3 8
9 14 15 5 2 8 12 3 7 0 4 10 1 13 11 6
4 3 2 12 9 5 15 10 11 14 1 7 6 0 8 13

S7:

4 11 2 14 15 0 8 13 3 12 9 7 5 10 6 1
13 0 11 7 4 9 1 10 14 3 5 12 2 15 8 6
1 4 11 13 12 3 7 14 10 15 6 8 0 5 9 2
6 11 13 8 1 4 10 7 9 5 0 15 14 2 3 12

S8:

13 2 8 4 6 15 11 1 10 9 3 14 5 0 12 7
1 15 13 8 10 3 7 4 12 5 6 11 0 14 9 2
7 11 4 1 9 12 14 2 0 6 10 13 15 3 5 8
2 1 14 7 4 10 8 13 15 12 9 0 3 5 6 11