首页 > Python资料 博客日记
对称加密算法——DES算法(包含Python、C、Java语言代码实现)
2024-11-02 16:00:07Python资料围观38次
一、算法原理
DES(数据加密标准)算法对明文数据进行16轮的替换和置换操作,每一轮都会生成一个不同的子密钥,并依次对数据块进行操作。
每一轮的加密过程
DES的每一轮都将64位的明文分为两个部分:左半部分(32位)和右半部分(32位)。加密操作实际上只对右半部分进行变换,而左半部分则直接参与异或运算。具体步骤如下:
1. 初始分组
- 将64位明文经过初始置换(Initial Permutation, IP),重新排列位的顺序,得到新的64位数据,并将其分为左右两部分:
- 左半部分:L₀(32位)
- 右半部分:R₀(32位)
2. 16轮迭代加密
每一轮都会使用不同的子密钥 (K_i),并将当前轮的左半部分 (L_i) 和右半部分 (R_i) 进行如下操作:
-
步骤 1:将前一轮的右半部分 (R_{i-1}) 作为这一轮的新左半部分,即:
L_i = R_{i-1}
-
步骤 2:将前一轮的右半部分 (R_{i-1}) 送入 F函数,并与当前轮的子密钥 (K_i) 进行操作。F函数的详细步骤见后续。F函数的输出结果与前一轮的左半部分 (L_{i-1}) 进行异或运算,生成这一轮的新右半部分 (R_i),即:
R_i = L_{i-1} ⊕ F(R_{i-1}, K_i) -
步骤 3:继续进行下一轮。经过16轮后,左半部分和右半部分合并,形成64位的加密数据。
在每一轮操作中,左右两部分交换一次位置,从而保证密文与明文之间的复杂关系。
3. F函数(核心加密步骤)
F函数是DES算法中的关键步骤,用于生成复杂的加密结果。F函数将32位的右半部分 (R_{i-1}) 和48位的子密钥 (K_i) 结合起来,具体操作如下:
-
扩展置换(E扩展):
32位的右半部分 (R_{i-1}) 经过扩展置换操作,变成48位,扩展时根据一定的规则重复某些位。这一步的作用是增加密文的混淆性,并使其与48位的子密钥 (K_i) 进行异或操作。 -
异或运算:
将扩展后的48位数据与48位的子密钥 (K_i) 进行异或运算,得到48位的新数据。 -
S盒替代:
将48位数据分成8组,每组6位(48位/6),然后使用8个不同的S盒(Substitution box,替代盒)对每组6位进行替代。S盒的作用是将6位的输入转化为4位的输出,从而将48位数据变成32位。每个S盒都有一个特定的查表,用于根据输入的6位值确定输出的4位值。S盒是DES中最重要的非线性变换步骤,是加密过程产生混淆的关键。
-
置换操作(P盒置换):
对S盒替代后的32位输出进行置换操作,将数据位重新排列,增加混淆性。经过这一置换操作后,得到最终的32位输出结果。
F函数的输出与当前轮的左半部分进行异或运算,完成这一轮的加密。
4. 16轮加密结束
在完成16轮加密后,得到两个部分:左半部分 (L_{16}) 和右半部分 (R_{16})。此时将这两个部分组合在一起,并进行逆初始置换(Inverse Initial Permutation, IP⁻¹),得到最终的64位密文。
密钥生成过程
DES使用的是一个56位的主密钥(尽管输入是64位的,但其中每8位用于校验,只留下56位用于实际加密),然后通过一系列的位移和置换操作,从这个主密钥中生成16个子密钥,每个子密钥长度为48位。
-
去掉奇偶校验位:
虽然输入的密钥是64位,但每8位中的第8位是奇偶校验位。因此,首先需要将64位的密钥中的校验位去除,剩下56位用于密钥生成。 -
密钥置换选择 1(PC-1):
对去除校验位后的56位密钥进行第一次置换,称为置换选择1(Permutation Choice 1,PC-1)。PC-1会根据固定规则重新排列这56位密钥,将其分为两部分:左半部分 (C_0) 和右半部分 (D_0),每部分28位。初始56位密钥 -> PC-1 -> 28位的 C_0 和 28位的 D_0
-
左移操作:
在每一轮加密开始时,都会对(C_0) 和 (D_0) 进行左移操作。左移的位数不是固定的,而是根据当前轮次决定的。具体来说,每一轮的左移位数如下:- 第1、2、9、16轮:左移1位
- 其他轮:左移2位
每一轮左移后的值会生成新的 (C_i) 和 (D_i)。
注意是循环左移
C_0, D_0 -> 左移 -> C_1, D_1 -> 左移 -> C_2, D_2 -> …… -> C_16, D_16
-
密钥置换选择 2(PC-2):
左移之后,将 (C_i) 和 (D_i) 组合成56位的密钥,然后使用置换选择2(Permutation Choice 2,PC-2)将这56位压缩为48位。这是通过从56位中选择48位进行排列完成的。PC-2的目的是通过重新选择位的位置并减少位数来生成本轮的子密钥 (K_i)(48位)。56位的 C_i + D_i -> PC-2 -> 48位的子密钥 K_i
-
生成16个子密钥:
通过左移和置换选择2的操作,DES一共会生成16个不同的48位子密钥 (K_1, K_2, …, K_{16}),分别用于每一轮的加密运算。
二、代码实例
1.Python版
# 将十六进制字符串转为二进制字符串
def hex_to_bin(hex_str):
bin_str = bin(int(hex_str, 16))[2:].zfill(len(hex_str) * 4)
return bin_str
# 将二进制字符串转为十六进制字符串
def bin_to_hex(bin_str):
hex_str = hex(int(bin_str, 2))[2:].upper().zfill(len(bin_str) // 4)
return hex_str
# DES初始置换表
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]
# 逆初始置换表
IP_INV = [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]
# 扩展置换表
E = [32, 1, 2, 3, 4, 5, 4, 5,
6, 7, 8, 9, 8, 9, 10, 11,
12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21,
22, 23, 24, 25, 24, 25, 26, 27,
28, 29, 28, 29, 30, 31, 32, 1]
# 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]],
]
# P盒置换表
P_BOX = [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]
# 置换选择1(PC-1)表
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]
# 置换选择2(PC-2)表
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]
# 子密钥生成左移位数
SHIFT_SCHEDULE = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
# 将输入密钥转为64位,并去除校验位得到56位密钥
def key_permutation(key):
# key = hex_to_bin(key)
print('密钥的key:', key)
key = ''.join(key[i - 1] for i in PC_1)
return key[:28], key[28:]
# 左移操作
def left_shift(key, shifts):
return key[shifts:] + key[:shifts]
# 根据C和D生成子密钥
def generate_subkeys(C, D):
subkeys = []
for shift in SHIFT_SCHEDULE:
C = left_shift(C, shift)
D = left_shift(D, shift)
subkey = C + D
# 这里也就是在PC_2的列表为下标,看subkey[i]是什么,全部赋值完后,加入到新的subkey中
subkey = ''.join(subkey[i - 1] for i in PC_2)
subkeys.append(subkey)
return subkeys
# 执行初始置换和逆置换
def permute(data, table):
return ''.join(data[i - 1] for i in table)
# 加密的核心f函数,包括扩展置换E、S盒和P盒
def f_function(R, K):
# 1. 扩展置换
R = ''.join(R[i - 1] for i in E)
# 2. 与子密钥K进行异或 字符格式转换 int(K, 2)
R = bin(int(R, 2) ^ int(K, 2))[2:].zfill(48)
# 3. 经过S盒压缩
result = ''
for i in range(8):
block = R[i * 6:(i + 1) * 6]
row = int(block[0] + block[5], 2)
col = int(block[1:5], 2)
result += bin(S_BOX[i][row][col])[2:].zfill(4)
# 4. 经过P盒置换
result = ''.join(result[i - 1] for i in P_BOX)
return result
# DES加密函数
def des_encrypt(plaintext, key):
# 1. 初始置换
plaintext = permute(plaintext, IP)
# 初始置换后的输出
print('初始置换后的输出:', plaintext)
# 2. 分成左右两部分
L, R = plaintext[:32], plaintext[32:]
print("R的值为:", R)
# 生成16轮子密钥
C, D = key_permutation(key) # 去掉奇偶校验位
subkeys = generate_subkeys(C, D) # 使用列表将每一层密钥存储起来
# 利用enumerate()函数,遍历密钥列表
for i, subkey in enumerate(subkeys, 1):
print(f"第{i}轮子密钥: {bin_to_hex(subkey)}")
# 3. 进行16轮加密
for i in range(16):
L_new = R
# 查看下变换前L的值
if i == 0:
print("第1轮的L变换前的值为:", L)
R_new = bin(int(L, 2) ^ int(f_function(R, subkeys[i]), 2))[2:].zfill(32)
L, R = L_new, R_new
if i == 0:
print("第1轮的R_new的值为:", R_new)
print(f"第1轮输出: L = {bin_to_hex(L)}, R = {bin_to_hex(R)}")
# 4. 合并L和R,逆初始置换
combined = R + L
ciphertext = permute(combined, IP_INV)
return bin_to_hex(ciphertext)
# 主函数
if __name__ == "__main__":
plaintext = "0123456789ABCDEF"
key = "133457799BBCDFF1"
# 转为二进制
plaintext_bin = hex_to_bin(plaintext)
key_bin = hex_to_bin(key)
print("明文的二进制:",plaintext_bin)
print("密钥的二进制:", key_bin)
# 加密
ciphertext = des_encrypt(plaintext_bin, key_bin)
print(f"最终密文: {ciphertext}")
2.C语言版
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLOCK_SIZE 64
// IP置换表
int 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};
// 逆初始置换表
int IP_INV[] = {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};
// E扩展置换表
int E[] = {32, 1, 2, 3, 4, 5, 4, 5,
6, 7, 8, 9, 8, 9, 10, 11,
12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21,
22, 23, 24, 25, 24, 25, 26, 27,
28, 29, 28, 29, 30, 31, 32, 1};
// S盒表
int S_BOX[8][4][16] = {
// 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}}
};
// P置换表
int P_BOX[] = {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};
// 左移位数表
int SHIFT_SCHEDULE[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
// 置换选择1(PC-1)表
int 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};
// 置换选择2(PC-2)表
int 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};
// 将十六进制字符串转换为二进制字符串
void hex_to_bin(char *hex_str, char *bin_str) {
char *p = hex_str;
while (*p) {
switch (*p) {
case '0': strcat(bin_str, "0000"); break;
case '1': strcat(bin_str, "0001"); break;
case '2': strcat(bin_str, "0010"); break;
case '3': strcat(bin_str, "0011"); break;
case '4': strcat(bin_str, "0100"); break;
case '5': strcat(bin_str, "0101"); break;
case '6': strcat(bin_str, "0110"); break;
case '7': strcat(bin_str, "0111"); break;
case '8': strcat(bin_str, "1000"); break;
case '9': strcat(bin_str, "1001"); break;
case 'A': strcat(bin_str, "1010"); break;
case 'B': strcat(bin_str, "1011"); break;
case 'C': strcat(bin_str, "1100"); break;
case 'D': strcat(bin_str, "1101"); break;
case 'E': strcat(bin_str, "1110"); break;
case 'F': strcat(bin_str, "1111"); break;
}
p++;
// printf("plaintext_bin:%s, p:%s \n", bin_str, p);
}
}
// 左移操作
void left_shift(char *key, int shifts) {
char temp[28];
strncpy(temp, key, shifts);
memmove(key, key + shifts, 28 - shifts);
strncpy(key + 28 - shifts, temp, shifts);
}
// 二进制转换成十六进制
void bin_to_hex(const char *bin_str) {
int len = strlen(bin_str);
int hex_index = 0;
char hex_str[len];
// 每4个二进制位转换为1个十六进制位
for (int i = 0; i < len; i += 4) {
int value = 0;
// 计算当前4位的二进制值
for (int j = 0; j < 4; j++) {
if (bin_str[i + j] == '1') {
value += (1 << (3 - j)); // 根据位置计算值
}
}
// 将计算的值转换为十六进制字符
if (value < 10) {
hex_str[hex_index++] = '0' + value; // 数字
} else {
hex_str[hex_index++] = 'A' + (value - 10); // 字母
}
}
hex_str[hex_index] = '\0'; // 添加字符串结束符
printf("加密后的密文(十六进制):%s\n", hex_str);
}
// 生成子密钥
void generate_subkeys(char *key, char subkeys[16][48]) {
char C[28], D[28];
char permuted_key[56];
// 进行PC-1置换
for (int i = 0; i < 56; i++) {
permuted_key[i] = key[PC_1[i] - 1];
}
// 分割C和D
strncpy(C, permuted_key, 28);
strncpy(D, permuted_key + 28, 28);
// 生成子密钥
for (int i = 0; i < 16; i++) {
left_shift(C, SHIFT_SCHEDULE[i]);
left_shift(D, SHIFT_SCHEDULE[i]);
// 合并C和D并进行PC-2置换
char CD[56];
strncpy(CD, C, 28);
strncpy(CD + 28, D, 28);
for (int j = 0; j < 48; j++) {
subkeys[i][j] = CD[PC_2[j] - 1];
}
printf("subkeys[%d]:%s\n", i, subkeys[i]);
bin_to_hex(subkeys[i]);
}
}
// 逆初始置换
void inverse_permutation(char *data, char *perm_data) {
for (int i = 0; i < 64; i++) {
perm_data[i] = data[IP_INV[i] - 1];
}
}
// E扩展置换
void expansion(char *data, char *expanded_data) {
for (int i = 0; i < 48; i++) {
expanded_data[i] = data[E[i] - 1];
}
expanded_data[48] = '\0'; // 添加终止字符
}
void int_to_bin_str(int value, char *bin_str) {
for (int i = 3; i >= 0; i--) {
bin_str[i] = (value % 2) + '0'; // 将二进制位转换为字符
value /= 2;
}
bin_str[4] = '\0'; // 确保字符串以 null 结束
}
// S盒替换
void sbox_substitution(char *data, char *sbox_output) {
sbox_output[0] = '\0'; // 初始化输出字符串
for (int i = 0; i < 8; i++) {
int row = 2 * (data[6 * i] - '0') + (data[6 * i + 5] - '0'); // 计算行
int col = 8 * (data[6 * i + 1] - '0') + 4 * (data[6 * i + 2] - '0') +
2 * (data[6 * i + 3] - '0') + (data[6 * i + 4] - '0'); // 计算列
int sbox_value = S_BOX[i][row][col]; // 从 S 盒获取值
char sbox_bin[5];
int_to_bin_str(sbox_value, sbox_bin); // 将 S 盒输出值转换为二进制字符串
strncat(sbox_output, sbox_bin, 4); // 连接到输出字符串
}
}
// P置换
void p_permutation(char *data, char *perm_data) {
for (int i = 0; i < 32; i++) {
perm_data[i] = data[P_BOX[i] - 1];
}
perm_data[32] = '\0'; // 添加终止字符
}
// 轮函数F
void f_function(char *right, char *subkey, char *output) {
char expanded_right[48] = {0};
expansion(right, expanded_right); // 扩展E
printf("expanded_right: %s\n", expanded_right);
// 与子密钥进行异或操作
for (int i = 0; i < 48; i++) {
expanded_right[i] = ((expanded_right[i] - '0') ^ (subkey[i] - '0')) + '0';
}
printf("expanded_right异或后的: %s\n", expanded_right);
// 通过S盒替换
char sbox_output[32] = {0};
sbox_substitution(expanded_right, sbox_output);
printf("expanded_rights盒sbox_output后的: %s\n", sbox_output);
// 通过P置换
p_permutation(sbox_output, output);
}
// 初始置换
void initial_permutation(char *data, char *perm_data) {
memset(perm_data, 0, 64); // 确保初始化为全0
for (int i = 0; i < 64; i++) {
perm_data[i] = data[IP[i] - 1];
// printf("perm_data length: %d\n", strlen(perm_data));
}
// 打印perm_data的长度
printf("perm_data length: %d\n", perm_data[64]);
}
// 16轮迭代加密
void des_encrypt(char *plaintext, char subkeys[16][48], char *ciphertext) {
char permuted_text[64] = {0};
initial_permutation(plaintext, permuted_text); // 初始置换
char left[33] = {0}, right[33] = {0};
strncpy(left, permuted_text, 32);
strncpy(right, permuted_text + 32, 32);
// printf("permuted_text_length: %d\n", strlen(permuted_text));
printf("permuted_left: %s\n", left);
printf("permuted_right: %s\n", right);
char f_result[33] = {0}, temp[33] = {0};
for (int i = 0; i < 16; i++) {
strncpy(temp, right, 32);
f_function(right, subkeys[i], f_result); // 计算F函数
printf("f_result: %s\n", f_result);
// 左边与F结果进行异或
for (int j = 0; j < 32; j++) {
right[j] = ((left[j] - '0') ^ (f_result[j] - '0')) + '0';
}
printf("f_result: %s\n", f_result);
strncpy(left, temp, 32);
}
// 合并左右部分
char combined[64] = {0};
strncpy(combined, right, 32);
strncat(combined, left, 32);
// 逆初始置换
inverse_permutation(combined, ciphertext);
}
// DES加密主函数
void des_main(char *plaintext_hex, char *key_hex, char *ciphertext_hex) {
char plaintext_bin[65] = {0};
char key_bin[65] = {0};
char ciphertext_bin[65] = {0};
char subkeys[16][48] = {0};
printf("plaintext_bin进入前:%s\n", plaintext_bin);
printf("plaintext_hex:%s\n",plaintext_hex);
hex_to_bin(plaintext_hex, plaintext_bin); // 明文转换为二进制
printf("plaintext_bin进入后:%s\n", plaintext_bin);
printf("key_bin进入前:%s\n", key_bin);
hex_to_bin(key_hex, key_bin); // 密钥转换为二进制
printf("key_bin进入后:%s\n", key_bin);
printf("key_bin total:%d\n", strlen(key_bin));
generate_subkeys(key_bin, subkeys); // 生成16轮子密钥
des_encrypt(plaintext_bin, subkeys, ciphertext_bin); // 执行加密
printf("加密后的密文(二进制):%s\n", ciphertext_bin);
bin_to_hex(ciphertext_bin);
}
int main() {
char plaintext[] = "0123456789ABCDEF";
char key[] = "133457799BBCDFF1";
char ciphertext[17] = {0};
des_main(plaintext, key, ciphertext);
return 0;
}
3.Java版
package bean;
import java.util.Arrays;
import org.w3c.dom.ls.LSOutput;
public class DES {
private static final int BLOCK_SIZE = 64;
// IP 置换表
private static final int[] 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};
// 逆初始置换表
private static final int[] IP_INV = {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};
// E 扩展置换表
private static final int[] E = {32, 1, 2, 3, 4, 5, 4, 5,
6, 7, 8, 9, 8, 9, 10, 11,
12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21,
22, 23, 24, 25, 24, 25, 26, 27,
28, 29, 28, 29, 30, 31, 32, 1};
// S 盒表
private static final int[][][] 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}}
};
// P 置换表
private static final int[] P_BOX = {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};
// PC-1 和 PC-2 置换表
private static final int[] 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,
27, 19, 11, 3, 26, 18, 10, 2};
private static final int[] 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};
private static final int[] SHIFT_SCHEDULE = {1, 1, 2, 2, 2, 2, 2, 2,
1, 2, 2, 2, 2, 2, 2, 1};
// 将十六进制字符串转换为二进制字符串
public static String hexToBin(String hexStr) {
StringBuilder binStr = new StringBuilder();
for (char ch : hexStr.toCharArray()) {
switch (ch) {
case '0': binStr.append("0000"); break;
case '1': binStr.append("0001"); break;
case '2': binStr.append("0010"); break;
case '3': binStr.append("0011"); break;
case '4': binStr.append("0100"); break;
case '5': binStr.append("0101"); break;
case '6': binStr.append("0110"); break;
case '7': binStr.append("0111"); break;
case '8': binStr.append("1000"); break;
case '9': binStr.append("1001"); break;
case 'A': binStr.append("1010"); break;
case 'B': binStr.append("1011"); break;
case 'C': binStr.append("1100"); break;
case 'D': binStr.append("1101"); break;
case 'E': binStr.append("1110"); break;
case 'F': binStr.append("1111"); break;
}
}
return binStr.toString();
}
// 左移操作
// private static String leftShift(String key, int shifts) {
// String temp = key.substring(0, shifts);
// key = key.substring(shifts) + temp;
// return key;
// }
//左移操作
private static String leftShift(String key, int shifts) {
// 左移操作
return key.substring(shifts) + key.substring(0, shifts);
}
// 二进制转换成十六进制
public static String binToHex(String binStr) {
StringBuilder hexStr = new StringBuilder();
int len = binStr.length();
for (int i = 0; i < len; i += 4) {
int value = Integer.parseInt(binStr.substring(i, i + 4), 2);
if (value < 10) {
hexStr.append(value);
} else {
hexStr.append((char) ('A' + (value - 10)));
}
}
return hexStr.toString();
}
// 生成子密钥
public static String[] generateSubkeys(String key) {
String[] subkeys = new String[16];
StringBuilder permutedKey = new StringBuilder(56);
// 进行PC-1置换
for (int i = 0; i < 56; i++) {
permutedKey.append(key.charAt(PC_1[i] - 1));
}
// 打印permutedKey的长度
System.out.printf("permutedKey: %s\n", permutedKey);
// 分割C和D
String C = permutedKey.substring(0, 28);
String D = permutedKey.substring(28);
System.out.printf("permutedKey C: %s\n", C);
System.out.printf("permutedKey D: %s\n", D);
// 生成子密钥
for (int i = 0; i < 16; i++) {
// 左移
C = leftShift(C, SHIFT_SCHEDULE[i]);
D = leftShift(D, SHIFT_SCHEDULE[i]);
System.out.printf("permutedKey C左移: %s\n", C);
System.out.printf("permutedKey D左移: %s\n", D);
// 合并C和D并进行PC-2置换
StringBuilder CD = new StringBuilder(C).append(D);
System.out.printf("permutedKey CD: %s\n", CD);
StringBuilder subkey = new StringBuilder(48);
// 进行PC-2置换
for (int j = 0; j < 48; j++) {
subkey.append(CD.charAt(PC_2[j] - 1));
}
subkeys[i] = subkey.toString();
System.out.printf("subkeys[%d]: %s\n", i, subkeys[i]);
System.out.printf("第%d次加密后的密钥(十六进制):%s\n", i+1,binToHex(subkeys[i]));
}
return subkeys;
}
// 逆初始置换
public static String inversePermutation(String data) {
StringBuilder permData = new StringBuilder(64);
for (int i = 0; i < 64; i++) {
permData.append(data.charAt(IP_INV[i] - 1));
}
return permData.toString();
}
// E扩展置换
public static String expansion(String data) {
StringBuilder expandedData = new StringBuilder(48);
for (int i = 0; i < 48; i++) {
expandedData.append(data.charAt(E[i] - 1));
}
return expandedData.toString();
}
// S盒替换
public static String sboxSubstitution(String data) {
StringBuilder sboxOutput = new StringBuilder();
for (int i = 0; i < 8; i++) {
int row = 2 * (data.charAt(6 * i) - '0') + (data.charAt(6 * i + 5) - '0');
int col = 8 * (data.charAt(6 * i + 1) - '0') + 4 * (data.charAt(6 * i + 2) - '0')
+ 2 * (data.charAt(6 * i + 3) - '0') + (data.charAt(6 * i + 4) - '0');
int sboxValue = S_BOX[i][row][col];
String sboxBin = String.format("%4s", Integer.toBinaryString(sboxValue)).replace(' ', '0');
sboxOutput.append(sboxBin);
}
return sboxOutput.toString();
}
// P置换
public static String pPermutation(String data) {
StringBuilder permData = new StringBuilder(32);
for (int i = 0; i < 32; i++) {
permData.append(data.charAt(P_BOX[i] - 1));
}
return permData.toString();
}
// 轮函数F
public static String fFunction(String right, String subkey) {
String expandedRight = expansion(right);
StringBuilder xorResult = new StringBuilder(48);
// 与子密钥进行异或操作
for (int i = 0; i < 48; i++) {
xorResult.append((char) ((expandedRight.charAt(i) - '0') ^ (subkey.charAt(i) - '0') + '0'));
}
// 通过S盒替换
String sboxOutput = sboxSubstitution(xorResult.toString());
// 通过P置换
return pPermutation(sboxOutput);
}
// 初始置换
public static String initialPermutation(String data) {
StringBuilder permData = new StringBuilder(64);
for (int i = 0; i < 64; i++) {
permData.append(data.charAt(IP[i] - 1));
}
return permData.toString();
}
// 16轮迭代加密
public static String desEncrypt(String plaintext, String[] subkeys) {
String permutedText = initialPermutation(plaintext);
String left = permutedText.substring(0, 32);
String right = permutedText.substring(32);
for (int i = 0; i < 16; i++) {
String temp = right;
String fResult = fFunction(right, subkeys[i]);
System.out.printf("fResult右边经过F函数:%s\n", fResult);
// 左边与F结果进行异或
StringBuilder newRight = new StringBuilder(32);
for (int j = 0; j < 32; j++) {
newRight.append((char) ((left.charAt(j) - '0') ^ (fResult.charAt(j) - '0') + '0'));
}
right = newRight.toString();
left = temp;
String combine = right + left;
// System.out.printf("加密后的密文(十六进制):%s\n", binToHex(combine));
System.out.printf("第%d次加密后的密文(十六进制):%s\n", i+1,binToHex(combine));
}
// 合并左右部分
String combined = right + left;
return inversePermutation(combined);
}
// DES加密主函数
public static void desMain(String plaintextHex, String keyHex) {
String plaintextBin = hexToBin(plaintextHex); // 明文转换为二进制
String keyBin = hexToBin(keyHex); // 密钥转换为二进制
// System.out.printf("加密后的密文(二进制):%s\n", keyBin);
String[] subkeys = generateSubkeys(keyBin); // 生成16轮子密钥
String ciphertextBin = desEncrypt(plaintextBin, subkeys); // 执行加密
System.out.printf("加密后的密文(二进制):%s\n", ciphertextBin);
System.out.printf("加密后的密文(十六进制):%s\n", binToHex(ciphertextBin));
}
public static void main(String[] args) {
String plaintext = "0123456789ABCDEF";
String key = "133457799BBCDFF1"; // 64位密钥
desMain(plaintext, key);
}
}
下面这个链接是结合例子讲解的,讲的不错
链接: DES加密算法介绍(含例子)
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Python与PyTorch的版本对应
- Anaconda版本和Python版本对应关系(持续更新...)
- Python pyinstaller打包exe最完整教程
- Could not build wheels for llama-cpp-python, which is required to install pyproject.toml-based proj