一、实验要求与目的
1) 复习Feistel结构原理
2) 复习3DES的算法原理
3) 学习3DES算法的编程实现
二、实验内容与步骤记录(只记录关键步骤与结果,可截图,但注意排版与图片大小)
设计步骤:
1.先学习DES,自上而下设计好DES的整体算法结构。
2.设计好字符串和字节流的转换函数,因为return的一般都是字符串形式,所以需要特别注意这个问题。
3.一步一步具体填充DES的流程,四大板块包括“初始置换与逆置换”“密钥生成函数”“f函数”“异或运算”。
4.最后考虑DES的三重变换,如果是用EEE模式,直接调用三次DES函数即可。
查验步骤:
1.验证子密钥生成过程:
2.验证R和L的迭代过程
三、Feistel结构轮函数F算法设计
Feistel结构主要是以下内容,核心是迭代。
L[i+1]=R[i],R[i+1]=L[i]+f(R[i],K[i+1])
F函数分为以下部分。
3.1 将32位的R[i]右半部分进行扩展,得到一个48位的数据块。
3.2 子密钥的生成
但是,我其实把子密钥的生成单独拎出来了,不在f函数内。因为F函数是在一个循环里面的。而子密钥的生成实际上生成的是一整块列表,因此提到外面更方便。
3.3 扩展开的R[i]与密钥异或,得到48位的比特流wait_to_S
3.4 进行S盒变换,之后用P盒替换。
四、源代码记录(关键代码需备注)(今日糖分)
今日糖分:但是老师说实验报告是需要打印出纸质版的,并且建议我们每个实验都写4页差不多了。如果ctrlcctrlv源代码,250+行,那么喜提11页实验报告,所以在报告上我只能代码截图。在这里我是把代码放出来了。
到达世界最高城,理塘!
def DES(m,key):
after_replace = replace(m)
# 初始化 L 和 R 的列表,用于存储 L0~L16, R0~R16
L = [''] * 17
R = [''] * 17
# 生成密钥
K = generate_keys(key)
# print(K)
# 设置初始的 L0 和 R0
L[0] = after_replace[:32]
R[0] = after_replace[32:]
for i in range(16):
L[i+1] = R[i]
temp = f(R[i],K[i+1])
R[i+1] = xor_bits(L[i],temp)
# print(f"L{i+1} = {L[i+1]}")
# print(f"R{i+1} = {R[i+1]}")
res = R[16] + L[16] # 注意顺序是 R16 + L16
b = inreplace(res)
return bin_to_str(b)
#--------------初始置换与逆置换----------------#
#初始置换函数
def replace(m):
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
]
return ''.join(m[i - 1] for i in IP)
def inreplace(m):
IP_inverse = [
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
]
return ''.join(m[i - 1] for i in IP_inverse)
#--------------初始置换与逆置换----------------#
#--------------密钥生成函数--------------#
#连接
def permute(bits, table):
return ''.join(bits[i - 1] for i in table)
#左移
def left_shift(bits, n):
return bits[n:] + bits[:n]
def generate_keys(k_64):
PC1 = [
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
]
PC2 = [
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_table = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
# Step 1: 初始置换 PC-1(64 -> 56)
k_56 = permute(k_64, PC1)
# Step 2: 拆分成 C 和 D,各28位
C = k_56[:28]
D = k_56[28:]
# Step 3: 每轮移位 + PC-2 生成子密钥
K = [''] * 17
for i in range(16):
shift = shift_table[i]
C = left_shift(C, shift)
D = left_shift(D, shift)
combined = C + D
K[i+1] = permute(combined, PC2)
return K
#--------------密钥生成函数--------------#
#--------------f函数--------------#
#扩展函数
def extend(m):
IP = [
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,
]
return ''.join(m[i - 1] for i in IP)
#S盒变换
def Schange(wait_to_S_48):
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]
]
]
result_32 = ''
for i in range(8):
block = wait_to_S_48[i * 6:(i + 1) * 6]
row = int(block[0] + block[5], 2)
col = int(block[1:5], 2)
s_value = S_BOX[i][row][col]
bin_value = format(s_value, '04b')
result_32 += bin_value
# 添加P置换
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
]
fnl_32 = ''.join(result_32[i - 1] for i in P)
return fnl_32
#f函数
def f(r_32,key_48):
after_extend_48 = extend(r_32)
wait_to_S = xor_bits(after_extend_48,key_48)
return Schange(wait_to_S)
#--------------f函数--------------#
#-------------异或运算通用版本----------------#
def xor_bits(bits1, bits2):
return ''.join('0' if b1 == b2 else '1' for b1, b2 in zip(bits1, bits2))
#-------------异或运算通用版本----------------#
#-------------转-----------#
def bin_to_str(b):
return ''.join(chr(int(b[i:i+8], 2)) for i in range(0, len(b), 8))
def str_to_bin(s):
return ''.join([format(ord(c), '08b') for c in s])
#-------------转-----------#
if __name__ == "__main__":
m1 = "Cryptosy"
m2 = "stem lab"
key1 = "12345678"
key2 = "abcdfegh"
key3 = "12345678"
# 将字符串转为比特流(字符串形式的0和1)
bit_stream1 = str_to_bin(m1)
bit_stream2 = str_to_bin(m2)
bit_streamk1 = str_to_bin(key1)
bit_streamk2 = str_to_bin(key2)
bit_streamk3 = str_to_bin(key3)
print("原始字符串:", m1)
print("比特流:", bit_stream1)
print("原始字符串:", m2)
print("比特流:", bit_stream2)
c1 = DES(bit_stream1, bit_streamk1)
c2 = DES(bit_stream2, bit_streamk1)
bit_streamc1 = str_to_bin(c1)
bit_streamc2 = str_to_bin(c2)
print("c1", c1)
print("比特流:", bit_streamc1)
print("c2:", c2)
print("比特流:", bit_streamc2)
c3 = DES(bit_streamc1, bit_streamk2)
c4 = DES(bit_streamc2, bit_streamk2)
bit_streamc3 = str_to_bin(c3)
bit_streamc4 = str_to_bin(c4)
print("c3:", c3)
print("比特流:", bit_streamc3)
print("c4:", c4)
print("比特流:", bit_streamc4)
c5 = DES(bit_streamc3, bit_streamk3)
c6 = DES(bit_streamc4, bit_streamk3)
print("加密结果:", c5)
print("加密结果:", c6)
五、实验思考
3DES算法与DES算法有什么区别?
答:3DES(Triple DES)相较于传统的DES算法,在安全性上有显著提升,主要体现在其更长的密钥长度和更高的破解难度。
DES:使用56位密钥,密钥空间为2⁵⁶,那么暴力破解密钥概率为1/2⁵⁶。在1998年,电子前哨基金会(EFF)构建的专用硬件“DES Cracker”成功在约4.5天内通过暴力破解攻破了DES加密。而在单个RTX 3070上,平均每秒可尝试约3.87亿个密钥,预计需要约215天完成整个密钥空间的搜索。
3DES:通过对每个数据块执行三次DES加密操作,使用三个独立的56位密钥,理论上密钥长度为168位, 由于“中间相遇攻击”(meet-in-the-middle attack)的存在,实际安全性约为112位。那么暴力破解密钥概率为1/2112。由于其更大的密钥空间,即使在大规模GPU集群上,暴力破解3DES仍被认为在当前技术条件下是不切实际的.
3DES通过三次应用DES算法,显著增加了密钥空间,从而大幅提升了安全性。与传统DES相比,3DES的密钥空间从2⁵⁶增加到2¹¹²,使得暴力破解所需的时间从几天增加到数百万年甚至更长。因此,在需要较高安全性的场景中,3DES比传统DES更为可靠。然而,考虑到性能和安全性的进一步提升,现代应用中更推荐使用AES等更先进的加密算法。
(博主人工调用AI生成,请仔细甄别。)