密码学系列之C/Python编程实现DES算法
<h1 id="des">DES</h1><h1 id="任务描述">任务描述</h1>
<p>编程实现DES的加密和解密算法,对明文“0x0123456789ABCDEF”进行加密,采用密钥“0x133457799BBCDFF1”,输出每一轮的加密结果和轮密钥,并对密文进行解密,输出解密后的结果。</p>
<p><img src="https://img2024.cnblogs.com/blog/3426414/202603/3426414-20260324214404085-1097004233.png" alt="Snipaste_2026-03-24_21-13-40" loading="lazy"></p>
<p>DES算法详细介绍我就不展开了,但是简略的过程如上。同样,有需要的读者适当考虑读全英文文献<sup></sup>,或者利用各个社区进行系统的学习。</p>
<h1 id="c">C</h1>
<pre><code class="language-C">#include <stdio.h>
#include <stdlib.h>
typedef unsigned char Byte;
typedef unsigned long long Bytes;
// 为Bytes定义Permutate函数
Bytes PermutateBytes(Bytes a, const int b[], int m, int n) {
Bytes c = 0;
for (int i = 0; i < n; i++) {
c = (c << 1) | ((a >> (m - b - 1)) & 1);
}
return c;
}
// 为Byte定义Permutate函数
Byte PermutateByte(Byte a, const Byte b[], int m, int n) {
Byte c = 0;
for (int i = 0; i < n; i++) {
c = (c << 1) | ((a >> (m - b - 1)) & 1);
}
return c;
}
// 交换两个Bytes类型的值
void swap(Bytes *a, Bytes *b) {
Bytes temp = *a;
*a = *b;
*b = temp;
}
Bytes IP(Bytes a) {
static int ip = {
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,
56, 48, 40, 32, 24, 16,8,0,
58, 50, 42, 34, 26, 18, 10,2,
60, 52, 44, 36, 28, 20, 12,4,
62, 54, 46, 38, 30, 22, 14,6
};
return PermutateBytes(a, ip, 64, 64);
}
Bytes FP(Bytes a) {
static int fp = {
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,
32,0, 40,8, 48, 16, 56, 24
};
return PermutateBytes(a, fp, 64, 64);
}
Bytes PC1(Bytes key) {
static int pc1_l = {
56, 48, 40, 32, 24, 16,8,0,
57, 49, 41, 33, 25, 17,9,1,
58, 50, 42, 34, 26, 18, 10,2,
59, 51, 43, 35
};
static int pc1_r = {
62, 54, 46, 38, 30, 22, 14,6,
61, 53, 45, 37, 29, 21, 13,5,
60, 52, 44, 36, 28, 20, 12,4,
27, 19, 11,3
};
return (PermutateBytes(key, pc1_l, 64, 28) << 28) | PermutateBytes(key, pc1_r, 64, 28);
}
Bytes PC2(Bytes key) {
static int pc2 = {
13, 16, 10, 23,0,4,2, 27,
14,5, 20,9, 22, 18, 11,3,
25,7, 15,6, 26, 19, 12,1,
40, 51, 30, 36, 46, 54, 29, 39,
50, 44, 32, 47, 43, 48, 38, 55,
33, 52, 45, 41, 49, 35, 28, 31
};
return PermutateBytes(key, pc2, 56, 48);
}
Bytes Rotate(Bytes a, int n) {
for (int i = 0; i < n; i++)
a = (a << 1 | (a >> 27 & 1)) & ((1 << 28) - 1);
return a;
}
void Keygen(Bytes key, Bytes keys[]) {
key = PC1(key);
Bytes l = key >> 28;
Bytes r = key ^ (l << 28);
int offset = {
1, 1, 2, 2, 2, 2, 2, 2,
1, 2, 2, 2, 2, 2, 2, 1
};
for (int i = 0; i < 16; i++) {
l = Rotate(l, offset);
r = Rotate(r, offset);
keys = PC2((l << 28) | r);
}
}
Bytes S(Bytes a) {
static Byte s_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
}, {
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
}, {
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
}, {
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,
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
}, {
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
}, {
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
}, {
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
}, {
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
}
};
Bytes res = 0;
static Byte p = {0, 5, 1, 2, 3, 4};
for (int i = 0; i < 8; i++) {
Byte b = (a >> ((7 - i) * 6)) & ((1 << 6) - 1);
b = PermutateByte(b, p, 6, 6);
res = (res << 4) | s_box;
}
return res;
}
Bytes P(Bytes a) {
static int p = {
15,6, 19, 20, 28, 11, 27, 16,
0, 14, 22, 25,4, 17, 30,9,
1,7, 23, 13, 31, 26,2,8,
18, 12, 29,5, 21, 10,3, 24
};
return PermutateBytes(a, p, 32, 32);
}
Bytes Expand(Bytes a) {
static int e = {
31,0,1,2,3,4,3,4,
5,6,7,8,7,8,9, 10,
11, 12, 11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20, 19, 20,
21, 22, 23, 24, 23, 24, 25, 26,
27, 28, 27, 28, 29, 30, 31,0
};
return PermutateBytes(a, e, 32, 48);
}
Bytes Round(Bytes a, Bytes subkey) {
Bytes t = Expand(a) ^ subkey;
t = S(t);
t = P(t);
return t;
}
Bytes Feistel(Bytes a, Bytes subkey) {
Bytes l = a >> 32;
Bytes r = a ^ (l << 32);
return (r << 32) | (l ^ Round(r, subkey));
}
Bytes DES(Bytes m, Bytes key, int decrypt, int round) {
Bytes keys = {0};
Keygen(key, keys);
if (decrypt) {
for (int i = 0; i < 8; i++)
swap(&keys, &keys);
}
Bytes c = IP(m);
for (int i = 0; i < round; i++)
c = Feistel(c, keys);
Bytes l = c >> 32;
Bytes r = c ^ (l << 32);
return FP((r << 32) | l);
}
Bytes Encrypt(Bytes m, int round) {
return DES(m, 0xcafababedeadbeafULL, 0, round);
}
void test() {
printf("Test rotate: ");
if (Rotate(167772165, 2) == 134217750) {
printf("OK.\n");
} else {
printf("GG!\n");
}
printf("Test IP: ");
if (IP(81985529216486895ULL) == 14699974583363760298ULL) {
printf("OK.\n");
} else {
printf("GG!\n");
}
printf("Test PC1: ");
if (PC1(1383827165325090801ULL) == 67779029043144591ULL) {
printf("OK.\n");
} else {
printf("GG!\n");
}
printf("Test keygen: ");
Bytes keys = {0};
Keygen(1383827165325090801ULL, keys);
if (keys == 223465186400245ULL) {
printf("OK.\n");
} else {
printf("GG!\n");
}
printf("Test S box: ");
if (S(178261171038007ULL) == 3725222752ULL) {
printf("OK.\n");
} else {
printf("GG!\n");
}
printf("Test round: ");
if (Round(3707429454ULL, 141493528337059ULL) == 3207079049ULL) {
printf("OK.\n");
} else {
printf("GG!\n");
}
}
int main() {
test();
Bytes m = 0x0123456789ABCDEF;
Bytes k = 0x133457799BBCDFF1;
// 生成轮密钥
Bytes round_keys;
Keygen(k, round_keys);
// 执行加密过程并输出每一轮的加密结果和轮密钥
Bytes d = m;
printf("Round 0 - Input: %016llx\n", d);
for (int i = 0; i < 16; i++) {
d = DES(d, round_keys, 0, i + 1);
printf("Round %d - Output: %016llx, Round Key: %016llx\n", i + 1, d, round_keys);
}
Bytes c = DES(m, k, 0, 16);
printf("%016llx\n", c);
printf("%016llx\n", DES(c, k, 1, 16));
return 0;
}
</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/3426414/202603/3426414-20260324214426409-442686453.png" alt="Snipaste_2026-03-23_23-06-20" loading="lazy"></p>
<p>简单转换为Python了,但是本质上还是C语言的思维在发挥作用。</p>
<h1 id="python">Python</h1>
<pre><code class="language-python">#!/usr/bin/env python3
"""
DES加密算法的Python实现
基于C代码转换,包含完整的置换、S盒、密钥生成和Feistel网络
"""
# 类型别名
Byte = int
Bytes = int
# 通用置换函数(用于任意位数)
def permutate_bytes(a: Bytes, table: list, m: int, n: int) -> Bytes:
"""
根据置换表从输入a中提取位,生成新值
a: 输入整数
table: 置换表,元素为源位索引(0-based,从最高位开始计数)
m: 输入位数
n: 输出位数
"""
c = 0
for i in range(n):
# 获取第table位的值(从最高位算起)
bit = (a >> (m - table - 1)) & 1
c = (c << 1) | bit
return c
# 字节置换(用于6位输入/输出,但可通用)
def permutate_byte(a: Byte, table: list, m: int, n: int) -> Byte:
return permutate_bytes(a, table, m, n)
# 交换两个Bytes值
def swap(a: Bytes, b: Bytes) -> tuple:
return b, a
# ---------- 置换表 ----------
IP_TABLE = [
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,
56, 48, 40, 32, 24, 16,8,0,
58, 50, 42, 34, 26, 18, 10,2,
60, 52, 44, 36, 28, 20, 12,4,
62, 54, 46, 38, 30, 22, 14,6
]
FP_TABLE = [
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,
32,0, 40,8, 48, 16, 56, 24
]
PC1_L = [
56, 48, 40, 32, 24, 16,8,0,
57, 49, 41, 33, 25, 17,9,1,
58, 50, 42, 34, 26, 18, 10,2,
59, 51, 43, 35
]
PC1_R = [
62, 54, 46, 38, 30, 22, 14,6,
61, 53, 45, 37, 29, 21, 13,5,
60, 52, 44, 36, 28, 20, 12,4,
27, 19, 11,3
]
PC2_TABLE = [
13, 16, 10, 23,0,4,2, 27,
14,5, 20,9, 22, 18, 11,3,
25,7, 15,6, 26, 19, 12,1,
40, 51, 30, 36, 46, 54, 29, 39,
50, 44, 32, 47, 43, 48, 38, 55,
33, 52, 45, 41, 49, 35, 28, 31
]
P_TABLE = [
15,6, 19, 20, 28, 11, 27, 16,
0, 14, 22, 25,4, 17, 30,9,
1,7, 23, 13, 31, 26,2,8,
18, 12, 29,5, 21, 10,3, 24
]
E_TABLE = [
31,0,1,2,3,4,3,4,
5,6,7,8,7,8,9, 10,
11, 12, 11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20, 19, 20,
21, 22, 23, 24, 23, 24, 25, 26,
27, 28, 27, 28, 29, 30, 31,0
]
# S盒
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,
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
],
[# 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
]
]
# S盒输出前的位重排(固定)
S_P =
# ---------- DES基本函数 ----------
def ip(a: Bytes) -> Bytes:
"""初始置换"""
return permutate_bytes(a, IP_TABLE, 64, 64)
def fp(a: Bytes) -> Bytes:
"""最终逆置换"""
return permutate_bytes(a, FP_TABLE, 64, 64)
def pc1(key: Bytes) -> Bytes:
"""密钥置换PC1,输出56位"""
left = permutate_bytes(key, PC1_L, 64, 28)
right = permutate_bytes(key, PC1_R, 64, 28)
return (left << 28) | right
def pc2(key: Bytes) -> Bytes:
"""密钥置换PC2,输入56位,输出48位"""
return permutate_bytes(key, PC2_TABLE, 56, 48)
def rotate(a: Bytes, n: int) -> Bytes:
"""循环左移28位(a是28位值)"""
for _ in range(n):
a = ((a << 1) | ((a >> 27) & 1)) & ((1 << 28) - 1)
return a
def keygen(key: Bytes, keys: list) -> None:
"""生成16个48位子密钥"""
key = pc1(key)
l = key >> 28
r = key & ((1 << 28) - 1)# 低28位
offsets =
for i in range(16):
l = rotate(l, offsets)
r = rotate(r, offsets)
combined = (l << 28) | r
keys = pc2(combined)
def s_box(a: Bytes) -> Bytes:
"""S盒替换,输入48位,输出32位"""
res = 0
for i in range(8):
# 取出第i组6位(从高位开始)
b = (a >> ((7 - i) * 6)) & ((1 << 6) - 1)
# 重排位(0,5,1,2,3,4)
b = permutate_byte(b, S_P, 6, 6)
res = (res << 4) | S_BOX
return res
def p(a: Bytes) -> Bytes:
"""P置换,输入32位,输出32位"""
return permutate_bytes(a, P_TABLE, 32, 32)
def expand(a: Bytes) -> Bytes:
"""扩展置换,输入32位,输出48位"""
return permutate_bytes(a, E_TABLE, 32, 48)
def round_func(a: Bytes, subkey: Bytes) -> Bytes:
"""一轮Feistel函数"""
t = expand(a) ^ subkey
t = s_box(t)
t = p(t)
return t
def feistel(a: Bytes, subkey: Bytes) -> Bytes:
"""一轮Feistel网络"""
l = a >> 32
r = a & ((1 << 32) - 1)
return (r << 32) | (l ^ round_func(r, subkey))
def des(m: Bytes, key: Bytes, decrypt: bool, rounds: int) -> Bytes:
"""
DES加密/解密
m: 64位明文/密文
key: 64位原始密钥
decrypt: False加密,True解密
rounds: 执行的轮数(最多16)
"""
# 生成16个子密钥
keys = * 16
keygen(key, keys)
if decrypt:
# 解密时逆序使用子密钥
for i in range(8):
keys, keys = keys, keys
# 初始置换
c = ip(m)
# 执行rounds轮
for i in range(rounds):
c = feistel(c, keys)
# 交换左右并逆置换
l = c >> 32
r = c & ((1 << 32) - 1)
return fp((r << 32) | l)
def encrypt(m: Bytes, rounds: int) -> Bytes:
"""使用固定密钥0xcafababedeadbeaf进行加密测试"""
return des(m, 0xcafababedeadbeaf, False, rounds)
# ---------- 测试函数 ----------
def test():
print("Test rotate: ", end='')
if rotate(167772165, 2) == 134217750:
print("OK.")
else:
print("GG!")
print("Test IP: ", end='')
if ip(81985529216486895) == 14699974583363760298:
print("OK.")
else:
print("GG!")
print("Test PC1: ", end='')
if pc1(1383827165325090801) == 67779029043144591:
print("OK.")
else:
print("GG!")
print("Test keygen: ", end='')
keys = * 16
keygen(1383827165325090801, keys)
if keys == 223465186400245:
print("OK.")
else:
print("GG!")
print("Test S box: ", end='')
if s_box(178261171038007) == 3725222752:
print("OK.")
else:
print("GG!")
print("Test round: ", end='')
if round_func(3707429454, 141493528337059) == 3207079049:
print("OK.")
else:
print("GG!")
def main():
test()
m = 0x0123456789ABCDEF
k = 0x133457799BBCDFF1
# 生成轮密钥
round_keys = * 16
keygen(k, round_keys)
# 逐步加密并输出中间结果
d = m
print(f"Round 0 - Input: {d:016x}")
for i in range(16):
d = des(d, round_keys, False, i + 1)
print(f"Round {i+1:2d} - Output: {d:016x}, Round Key: {round_keys:016x}")
# 完整加密
c = des(m, k, False, 16)
print(f"使用密钥进行16轮行移位得到的结果为:{c:016x}")
# 解密验证
dec = des(c, k, True, 16)
print(f"原始的输入值为: {dec:016x}")
if __name__ == "__main__":
main()
</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/3426414/202603/3426414-20260324214447639-691062122.png" alt="Snipaste_2026-03-24_09-48-57" loading="lazy"></p>
<p>参考文章:Data Encryption Standard (DES) | Set 1 - GeeksforGeeks</p>
<h2 id="彩蛋时间">彩蛋时间</h2>
<p>代码图片生成器推荐,浏览器搜索Carbon。<br>
<img src="https://img2024.cnblogs.com/blog/3426414/202603/3426414-20260324214506247-1781727916.png" alt="b905f712-cb6d-4361-97bc-71c9d2a16f7f" loading="lazy"></p><br><br>
来源:https://www.cnblogs.com/red1giant-star/p/19766226
頁:
[1]