Status
Done
参考文档
一、关于DES运作的简介:
Data Encryption Standard(DES),数据加密标准,是典型的块加密,其基本信息如下:
- 将要机密的明文分成n个64 位的数据块进行输入
- 加密后的密文同样为 64 位
- 密钥长度为 64 位,使用 64 位密钥中的 56 位进行加密(原始密钥中每字节的最高位是没有被使用的),剩余的 8 位要么丢弃,要么作为奇偶校验位
- Feistel 迭代结构:
- 明文经过 16 轮迭代得到密文
- 密文经过类似的 16 轮迭代得到明文
二、DES加密过程分析:
1.加密过程简介:

主要的加密流程:
- 将输入的明文进行初始置换。
- 将初始置换后的结果按照每组32位数据分成Ln、Rn两组。
- Rn经过扩展置换从32位变成48位
- 输入的64位密钥经过处理得到48位的密钥(具体的处理过程在下面单独分析)
- 将48位的Rn与48位的密钥就行异或,得出的值进行S盒压缩成32位数据
- 压缩后的值进行P盒置换(P盒置换对应的是扩展置换操作)
- 最后将值存入L(n+1),然后Rn的值存的是当前加密轮数啥事也没干的Ln
- 对4~7步处理进行16次循环,得到L[16],R[16]
- 将L[16]、R[16]数据进行交叉合并得到64位数据
- 对得到的64位数据进行逆初始值置换,得到想要的密文Y
2.加密过程中的难点分析:
1.初始置换:
首先,DES会对用户的输入进行处理,称为初始置换(Initial Permutation),用户的输入将会按照下图的顺序进行置换。(这里的操作就是将输入的64位明文按照指定的顺序重新排列)

假设用户的输入位M,经过置换后的结果为IP:
代码实现
2.扩展置换
经过初始置换后的64位数据(IP),被分成了等长的左右两部分,可以获得初始的L和R的值:
其中右边的32位将被进行扩展置换得到48位的数据。具体的扩展过程为下图:

其实就是在固定的位置进行了添位操作,而且添加的值也都是原输入里面特定位置的值:

看着个图,添位过程就是先将输入的32位以4个位为一组分成八组,每组的前后都要添加一个位的值。
- 当前组的第一位,放在前面一组的后面需要添位的地方。
- 当前组的最后一位,放在后面一组的前面需要添位的地方。
(这里有点绕可以对着图理一下)
最后R0里的值为(总共48位)
3.S盒的压缩:
经过扩展的48位明文与48位密钥进行异或运算后,得到48位的数据。这48位数据分为8组,每组6位作为一个S盒的输入,而S盒的输出为4位,具体的处理方式是分别用8张4行16列的表来进行压缩
S盒1
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 |
S盒2
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 |
S盒3
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 |
S盒4
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 | 19 |
10 | 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 |
S盒5
2 | 12 | 4 | 1 | 7 | 10 | 11 | 6 | 5 | 8 | 3 | 15 | 13 | 0 | 14 | 9 |
14 | 11 | 2 | 12 | 4 | 7 | 13 | 1 | 5 | 0 | 15 | 13 | 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 |
S盒6
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 |
S盒7
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 |
S盒8
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 |
For Example:

如图使用8个S盒压缩处理得到32位数据
代码实现
4.P盒置换:
S盒压缩后的的32位数据需要按照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 |
之后将P盒置换的结果与啥事也没做的左半部分L0异或,然后进行交换赋值到L1和R1,大概的操作是:
接着开始新的一轮运算
代码实现
5.终止置换:
仔细观察初始置换表和终止置换表后会发现它们的排列是互逆的(一开始明文的第一位被放在了第40位处,最后又放回来了),也就是说经过一次初始置换和一次终止置换后64位二进制的位置又还原了

6.key的生成方式:

首先,对传入的64位密钥同样进行置换但是,这里注意对于原始的64位密钥里的每字节的最高为是没有被使用的,一般这个最高位要么被弃用要么作为奇偶校验位,这样一来64位的密钥经过置换得到的密钥就变成了56位,具体置换表如下:(注意这里没有第8,16,2432,40,48,56和64位)
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 |
For Example:
置换完后等于56位的数,然后将其分成两部分C0和D0:(分成两个28位)
在DES加密的16轮中,每次的key是不一样的,那怎么个不一样法呢:
当我们获得C0和D0后其实是通过循环左移操作生成新的数据后,经过一个置换表后得出一个46位的key,这个key就是每轮用来异或的key,下面我们仔细分析一下具体的实现:
首先是考虑左移是怎么左移的:
C0和D0分别循环左移,每轮左移的位数是根据左移表来的:
1 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 1 |
将每组Cn和Dn进行组合,就得到了16组数据,每组数据都是56位。
代码实现
下面考虑的就是将56位的数据通过置换表得到46位的key,在压缩过程中第9、18、22、25、35、38、43、54共8位数据被丢掉:
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 |
代码实现
三、DES加解密
python加解密脚本:
补充:DES算法在CTF逆向中的应用
特征总结:
- 密文的长度必须是0x08字节的倍数。
- 秘钥的长度必须是 0x08字节。
- 可以尝试找一些表的特征比如循环左移表,置换表等等
名称
难度
难点