✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆
🔥系列专栏 :简单外包单
📃新人博主 :欢迎点赞收藏关注,会回访!
💬舞台再大,你不上台,永远是个观众。平台再好,你不参与,永远是局外人。能力再大,你不行动,只能看别人成功!没有人会关心你付出过多少努力,撑得累不累,摔得痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷。
文章目录
- 实验二 DES密码算法的设计与实现
- 一、实验目的
- 二、实验任务
- 三、实验环境
- 四、实验原理
- 五、程序设计核心代码
- 六、实验结果及软件使用说明
- 七、源代码
实验二 DES密码算法的设计与实现
一、实验目的
通过用DES算法对实际的数据进行加密和解密,并撰写实验报告,深刻理解DES算法的设计机制、分组密码算法工作模式。
二、实验任务
(1) 设计并实现DES加解密算法;(提供图形界面,必做)
(2) 能用DES加解密算法对字符串文本进行加解密,记录运行时间(必做),对文件进行加解密(扩展);
(3) 设计并实现ECB、CBC工作模式的加解密算法;(必做)
(4) 设计并实现3DES加解密算法(扩展);
(5) 提供图形化用户界面,并提交核心程序代码和执行结果。(必做)
(6) 使用(3)中实现的程序,对输入的字符数据进行加密,比较输入和输出。当把输入的数据改变时,比较输出的变化,并说明原因。(必做)。
三、实验环境
信息楼西505,Windows10,python3.9.7
四、实验原理
1、初始置换:
DES算法使用64位的密钥key将64位的明文输入块变为64位的密文输出块,并把输出块分为L0、R0两部分,每部分均为32位。初始置换规则如下(注意:这里的数字表示的是原数据的位置,不是数据)即将输入的64位明文的第1位置换到第40位,第2位置换到第8位,第3位置换到第48位。以此类推,最后一位是原来的第7位。置换规则是规定的。L0(Left)是置换后的数据的前32位,R0(Right)是置换后的数据的后32位。
例如:64位输入块是D1~D64,则经过初始置换后是D58,D50…D7。则L0=D58,D50,D12…D8;R0=D57,D49,D41…D7。
该置换过程是在64位秘钥的控制下。
2、加密处理–16轮迭代过程:
经过初始置换后,进行16轮完全相同的运算,在运算过程总数据与密钥结合。函数f的输出经过一个异或运算,和左半部分结合形成新的右半部分,原来的右半部分成为新的左半部分。每轮迭代的过程可以表示如下:
Ln = R(n - 1);
Rn = L(n - 1)⊕f(Rn-1,kn-1)
⊕:异或运算
Kn是向第N层输入的48位的秘钥,f是以Rn-1和Kn为变量的输出32位的函数
函数f由四步运算构成:秘钥置换(Kn的生成,n=0~16);扩展置换;S-盒代替;P-盒置换。
2.1 秘钥置换–子密钥生成:
DES算法由64位秘钥产生16轮的48位子秘钥。在每一轮的迭代过程中,使用不同的子秘钥。
(1)把密钥的奇偶校验位忽略不参与计算(即每个字节的第8位),将64位密钥降至56位,然后根据选 择置换PC-1 将这56位分成两块C0(28位)和D0(28位);
(2)将C0和D0进行循环左移变化(每轮循环左移的位数由轮数决定),变换后生成C1和D1,然后C1和D1合并,并通过 选择置换PC-2 生成子密钥K1(48位);
(3)C1和D1再次经过循环左移变换,生成C2和D2,然后C2和D2合并,通过 选择置换PC-2 生成密钥K2(48位);
(4)以此类推,得到K16(48位)。但是最后一轮的左右两部分不交换,而是直接合并在一起R16L16,作为逆置换的输入块。其中循环左移的位数一共是循环左移16次,其中第一次、第二次、第九次、第十六次是循环左移一位,其他都是左移两位。
2.2 S-盒代替(功能表S盒)
Rn扩展置换之后与子秘钥Kn异或以后的结果 作为输入块进行S盒代替运算,功能是把48位数据变为32位数据,代替运算由8个不同的代替盒(S盒)完成。每个S-盒有6位输入,4位输出。所以48位的输入块被分成8个6位的分组,每一个分组对应一个S-盒代替操作。经过S-盒代替,形成8个4位分组结果。
注意:每一个S-盒的输入数据是6位,输出数据是4位,但是每个S-盒自身是64位!!每个S-盒是4行16列的格式,因为二进制4位是0~15。
将32位的输入的第16位放在第一位,第七位放在第二位,第二十位放在第三位,以此类推。最后生成L16和R16,其中R16为L15与P盒置换结果做异或运算的结果,L16是R15的直接赋值。
3、逆置换:
将初始置换进行16次的迭代,即进行16层的加密变换,这个运算过程我们暂时称为函数f。得到L16和R16,将此作为输入块,进行逆置换得到最终的密文输出块。逆置换是初始置换的逆运算。从初始置换规则中可以看到,原始数据的第1位置换到了第40位,第2位置换到了第8位。则逆置换就是将第40位置换到第1位,第8位置换到第2位。
五、程序设计核心代码
cipher(message, key, mode=‘encrypt’): 这个函数用于执行DES加密和解密的核心操作。输入参数包括:
message: 待加密或解密的消息,以字符串表示的16进制明文或密文。
key: 加密密钥,以字符串表示的16进制。
mode: 加密或解密模式,默认为加密。可以设置为 ‘encrypt’ 或 ‘decrypt’。
输出是经过DES加密或解密后的结果,以字符串表示的16进制。
- def cipher(message, key, mode=‘encrypt’):
-
subkeys = CreateSubKeys(key) **if** mode == 'encrypt' **else** CreateSubKeys(key)[::-1] # 顺序相反取密钥
-
text = IpPermutation(message)
-
**for** i **in** range(16):
-
l, r = text[:32], text[32:]
-
r_extend = ExtendPermutation(r)
-
xor1 = xor(r_extend, subkeys[i])
-
s_box_result = SBoxPermutation(xor1)
-
p_box_result = PBoxPermutation(s_box_result)
-
xor2 = xor(l, p_box_result)
-
text = r + xor2
-
text = text[32:] + text[:32]
-
**return** InverseIpPermutation(text)
fill(message): 这个函数用于对消息进行填充,以确保字符分组长度为64的整数倍。如果消息长度不是64的整数倍,就用默认字符 “0” 补全到下一个64位的整数倍。
- def fill(message):
-
'''''
-
填充函数,若字符分组长度不为16的倍数,使用默认字符“0”补全为16的整数倍。
-
'''
-
**try**:
-
mod = len(message) % 64
-
space = 64 - mod
-
**while**(space > 0):
-
message = message.append("0")
-
space -= 1
-
**return** message
-
**except** AttributeError:
-
**print**(message)
DES加密器(DES_encrypter类)和解密器(DES_decrypter类)
init(self, message, key, mean, iv): 初始化函数,接收以下参数:
message: 待加密或解密的消息,以字符串表示的16进制明文或密文。
key: 加密密钥,以字符串表示的16进制。
mean: 操作方式,指定加密或解密模式(‘ECB’, ‘CBC’, ‘CFB’, ‘OFB’)。
iv: 初始化向量,以字符串表示的16进制。
ciphertext(加密器的属性): 返回经过DES加密后的结果,以字符串表示的16进制。
plaintext(解密器的属性): 返回经过DES解密后的结果,以字符串表示的16进制。
加密模式函数:
__ECBencrypt: 密码本模式的加密操作。
__CBCencrypt: 密码块链接模式的加密操作。
__CFBencrypt: 密码反馈模式的加密操作。
__OFBencrypt: 输出反馈模式的加密操作。
解密模式函数:
__ECBdecrypt: 密码本模式的解密操作。
__CBCdecrypt: 密码块链接模式的解密操作。
__CFBdecrypt: 密码反馈模式的解密操作。
__OFBdecrypt: 输出反馈模式的解密操作。
核心代码:
-
dex2bin4 函数:将十进制数(不超过15)转换为4位二进制字符串。
使用bin函数获取二进制字符串表示,去除前缀"0b"。
补零使其长度为4。
dex2bin8 函数:将十进制数转换为8位二进制字符串。
使用bin函数获取二进制字符串表示,去除前缀"0b"。
补零使其长度为8。 -
def dex2bin4(dex):
-
'''''
-
将(不超过15的)十进制数转化成4位二进制字符串。
-
如:13 -> '1101'。
-
'''
-
temp = bin(dex).replace('0b', '')
-
length = len(temp)
-
addzero = '0' * (4 - length) # 不足四位的在前面补0
-
**return** addzero + temp
-
SBoxPermutation 函数:
对48位输入进行S-盒置换。
将48位分成8个6位小组,每个小组进入相应的S盒。
获取S盒中的值,转换为4位二进制表示。
将所有小组得到的32位结果合并。 -
def SBoxPermutation(text):
-
'''''S-盒置换:将48位输入均分成长度为6的8个小组,每个小组按顺序进入相应的S盒各得到4位输出,返回合并后的32位结果。'''
-
result = []
-
**for** i **in** range(0, 8):
-
temp = text[i * 6:i * 6 + 6]
-
row = int(str(temp[0]) + str(temp[-1]), 2)
-
column = int(str(temp[1]) + str(temp[2]) + str(temp[3]) + str(temp[4]), 2)
-
letter = S_BOX[i][row][column]
-
result.append(dex2bin4(letter))
-
**return** [int(x) **for** x **in** ''.join(result)]
-
PBoxPermutation 函数:
对32位输入按P-盒规则置换。
使用P盒置换规则进行置换。 -
def PBoxPermutation(text):
-
'''''P-盒置换:将32位输入按 P 规则置换后返回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]
-
**return** [text[P[i] - 1] **for** i **in** range(32)]
-
xor 函数:
对两个序列进行各位异或操作。
返回异或结果。 -
def xor(m, n):
-
'''''对两个序列进行各位异或操作,并返回所得结果。'''
-
**return** [a ^ b **for** a, b **in** zip(m, n)]
-
char2bin 函数:
返回ASCII字符的8位二进制表示。
使用ord函数获取字符ASCII码,再使用bin函数获取二进制表示。
补零使其长度为8。 -
def char2bin(char):
-
'''''
-
返回一个(ASCII)字符的8位二进制表示。
-
如:'A' -> '01000001'。
-
'''
-
b = bin(ord(char)).replace('0b', '')
-
space = 8 - len(b)
-
**return** '0' * space + b
-
string2bin 函数:
将包含16进制表示的字符串转化为包含64位二进制数字的列表。
对字符串中的每个16进制字符,使用int和bin函数转化为4位二进制字符串,再拼接在一起。
最终将字符串表示的二进制转换为整数列表。 -
def string2bin(text):
-
'''''
-
将含有16进制表示的字符串转化成包含64位二进制数字的列表。
-
'''
-
temp = ["{:0>4b}".format(int(char, 16)) **for** char **in** text]
-
temp = [int(number) **for** number **in** "".join(temp)]
-
**return** temp
-
bin2string 函数:
将64位二进制数字的列表以4位为一组转化为对应的16进制字符串。
对列表中的每4个二进制数,使用join方法拼接为一个字符串。
将每个字符串表示的16进制数字转换为整数,再转换为16进制字符串表示。 -
def bin2string(text):
-
'''''
-
将二进制数字的列表以4位为一组转化成对应16进制的字符串。
-
'''
-
length = len(text)
-
**if**(length % 4):
-
**return** False
-
text = [str(number) **for** number **in** text] # 先将列表里的 int 类型转化为 str 类型
-
result = []
-
**for** i **in** range(length // 4):
-
binstring = ''.join(text[i * 4:i * 4 + 4])
-
result.append(hex(int(binstring, 2))[2:]) # 去除16进制中的Hex
-
**return** ''.join(result)
六、实验结果及软件使用说明
图 1 替代密码主界面
使用说明:
首先输入秘钥Key和初始向量IV,然后选择加密的模式,Encrypt进行加密,Decrypt进行解密,Output输出结果。也可以打开文档加解密,下面是实现结果:
图 2 ECB加密数据
图 3 CBC加密数据
图 4 CFB加密数据
图 5 OFB加密数据
图 6 加密文档
图 7 解密文档
图 8 ECB解密
图 9 CBC解密
图 10 CFB解密
图 11 OFB解密
图 12 与主流软件相比 结果一致
七、源代码
# -*- coding: UTF-8 -*-
from operations import IpPermutation, InverseIpPermutation, ExtendPermutation, \
CreateSubKeys, SBoxPermutation, PBoxPermutation, \
string2bin, bin2string, xor
def cipher(message, key, mode='encrypt'):
subkeys = CreateSubKeys(key) if mode == 'encrypt' else CreateSubKeys(key)[::-1] # 顺序相反取密钥
text = IpPermutation(message)
for i in range(16):
l, r = text[:32], text[32:]
r_extend = ExtendPermutation(r)
xor1 = xor(r_extend, subkeys[i])
s_box_result = SBoxPermutation(xor1)
p_box_result = PBoxPermutation(s_box_result)
xor2 = xor(l, p_box_result)
text = r + xor2
text = text[32:] + text[:32]
return InverseIpPermutation(text)
def fill(message):
'''
填充函数,若字符分组长度不为16的倍数,使用默认字符“0”补全为16的整数倍。
'''
print(f"in fill, message{message}")
try:
mod = len(message) % 64
space = 64 - mod
while(space > 0):
# print(type(message))
message.append(0)
space -= 1
print("return message")
return message
except AttributeError:
print(message)
class DES_encrypter:
"""
DES加密器
message:字符串类型表示的16进制明文
key:加密密钥,字符串类型表示的16进制
mean:操作方式(ECB, CBC, CFB, OFB)
iv:字符串类型表示的16进制的初始化向量
"""
def __init__(self, message, key, mean, iv):
self.message = string2bin(message)
self.key = string2bin(key)
self.mean = mean
self.iv = string2bin(iv)
@property
def ciphertext(self):
if(self.mean == "ECB"):
return bin2string(self.__ECBencrypt())
if(self.mean == "CBC"):
return bin2string(self.__CBCencrypt())
if(self.mean == "CFB"):
return bin2string(self.__CFBencrypt())
else:
return bin2string(self.__OFBencrypt())
def __ECBencrypt(self):
"""密码本模式"""
output = []
length = len(self.message)
times, mod = length // 64, length % 64
if mod:
self.message = fill(self.message)
times += 1
for i in range(times):
result = cipher(self.message[i * 64:i * 64 + 64], self.key, 'encrypt')
output.extend(result)
return output
def __CBCencrypt(self):
"""密码块链接模式"""
output = []
length = len(self.message)
times, mod = length // 64, length % 64
print(f"length:{length},times:{times}, mod:{mod}")
if mod:
self.message = fill(self.message)
times += 1
print(f"self.message:{self.message}")
print(f"self.message:{self.message}")
lastrecord = self.iv
for i in range(times):
submessage = self.message[i * 64:i * 64 + 64]
print(f"submessage:{submessage}")
submessage = xor(submessage, lastrecord)
result = cipher(submessage, self.key, 'encrypt')
output.extend(result)
lastrecord = result
return output
def __CFBencrypt(self):
"""密码反馈模式
这里采用1字节反馈模式即一次仅加密明文8位,并更新寄存器中保存的密码流8位
"""
output = []
length = len(self.message)
times, mod = length // 8, length % 8
if mod:
space = 8 - mod
while(space > 0):
self.message = self.message.append("0")
space -= 1
times += 1
register = self.iv
for i in range(times):
submessage = self.message[i * 8:i * 8 + 8]
code = cipher(register, self.key, 'encrypt')
result = xor(code[0:8], submessage)
register = register[8:] + result[0:8]
output.extend(result)
return output
def __OFBencrypt(self):
"""输出反馈模式
与CFB相似,只不过密码流不再依赖明文或者生成的密文
同样采用1字节反馈模式
"""
output = []
length = len(self.message)
times, mod = length // 8, length % 8
if mod:
space = 8 - mod
while(space > 0):
self.message = self.message.append("0")
space -= 1
times += 1
register = self.iv
for i in range(times):
submessage = self.message[i * 8:i * 8 + 8]
code = cipher(register, self.key, 'encrypt')
result = xor(code[0:8], submessage)
register = register[8:] + code[0:8]
output.extend(result)
return output
class DES_decrypter:
"""DES解密器"""
def __init__(self, cipher, key, mean, iv):
self.cipher = string2bin(cipher)
self.key = string2bin(key)
self.mean = mean
self.iv = string2bin(iv)
@property
def plaintext(self):
if(self.mean == "ECB"):
return bin2string(self.__ECBdecrypt())
if(self.mean == "CBC"):
return bin2string(self.__CBCdecrypt())
if(self.mean == "CFB"):
return bin2string(self.__CFBdecrypt())
else:
return bin2string(self.__OFBdecrypt())
def __ECBdecrypt(self):
"""密码本模式"""
output = []
length = len(self.cipher)
times, mod = length // 64, length % 64
if mod:
self.cipher = fill(self.cipher)
times += 1
for i in range(times):
result = cipher(self.cipher[i * 64:i * 64 + 64], self.key, 'decrypt')
output.extend(result)
return output
def __CBCdecrypt(self):
"""密码块链接模式"""
output = []
length = len(self.cipher)
times, mod = length // 64, length % 64
print(f"times:{times}, mod:{mod}")
if mod:
self.cipher = fill(self.cipher)
times += 1
print(f"self.cipher:{self.cipher}")
lastrecord = self.iv
for i in range(times):
submessage = self.cipher[i * 64:i * 64 + 64]
submessage = cipher(submessage, self.key, 'dcrypt')
result = xor(submessage, lastrecord)
print(f"result:{result}")
output.extend(result)
lastrecord = self.cipher[(i) * 64:(i) * 64 + 64]
return output
def __CFBdecrypt(self):
"""密码反馈模式
"""
output = []
length = len(self.cipher)
times, mod = length // 8, length % 8
if mod:
space = 8 - mod
while(space > 0):
self.cipher = self.cipher.append("0")
space -= 1
times += 1
register = self.iv
for i in range(times):
subcipher = self.cipher[i * 8:i * 8 + 8]
code = cipher(register, self.key, 'encrypt')
result = xor(code[0:8], subcipher)
register = register[8:] + subcipher[0:8]
output.extend(result)
return output
def __OFBdecrypt(self):
"""密码反馈模式
"""
output = []
length = len(self.cipher)
times, mod = length // 8, length % 8
if mod:
space = 8 - mod
while(space > 0):
self.cipher = self.cipher.append("0")
space -= 1
times += 1
register = self.iv
for i in range(times):
subcipher = self.cipher[i * 8:i * 8 + 8]
code = cipher(register, self.key, 'encrypt')
result = xor(code[0:8], subcipher)
register = register[8:] + code[0:8]
output.extend(result)
return output
# -*- coding: UTF-8 -*-
__all__ = ['IpPermutation', 'InverseIpPermutation', 'CreateSubKeys',
'ExtendPermutation', 'SBoxPermutation', 'PBoxPermutation',
'xor', 'string2bin', 'bin2string']
def IpPermutation(text):
'''初始置换IP:将64位输入按 IP 规则置换后返回64位结果。'''
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 [text[IP[i] - 1] for i in range(64)]
def InverseIpPermutation(text):
'''逆初始置换IP^-1:将64位输入按 IP^-1 规则置换后返回64位结果。'''
INVERSE_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]
return [text[INVERSE_IP[i] - 1] for i in range(64)]
def ExtendPermutation(text):
'''扩展置换E:将32位输入按 E 规则置换后拓展为48位结果。'''
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]
return [text[E[i] - 1] for i in range(48)]
# 密钥调度所需的 PC-1 变换和 PC-2 变换
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]
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]
def shift(text, movetimes):
'''
对给定的序列,左移指定次数,并返回移动后的序列。
如:[1, 2, 3, 4] & movetimes = 1 -> [2, 3, 4, 1]。
'''
return text[movetimes:] + text[:movetimes]
def CreateSubKeys(primarykey):
'''根据主密钥,生成十六个轮密钥。'''
result = []
key56 = [primarykey[PC_1[i] - 1] for i in range(56)]
MOVETIMES = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
# 进行16轮子密钥生成
for i in range(16):
# 每28位为一部分,分别进行循环左移
key28left = shift(key56[:28], MOVETIMES[i])
key28right = shift(key56[28:], MOVETIMES[i])
key56 = key28left + key28right
# 对56位密钥进行 PC-2 变换,将其压缩为48位
key48 = [key56[PC_2[i] - 1] for i in range(48)]
result.append(key48)
return result
# 构建8个S-盒模型
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_BOX = [S1, S2, S3, S4, S5, S6, S7, S8]
def dex2bin4(dex):
'''
将(不超过15的)十进制数转化成4位二进制字符串。
如:13 -> '1101'。
'''
temp = bin(dex).replace('0b', '')
length = len(temp)
addzero = '0' * (4 - length) # 不足四位的在前面补0
return addzero + temp
def dex2bin8(dex):
'''
将十进制数转化成8位二进制字符串。
如:90 -> '01011010'
'''
temp = bin(dex).replace('0b', '')
length = len(temp)
addzero = '0' * (8 - length) # 不足四位的在前面补0
return addzero + temp
def SBoxPermutation(text):
'''S-盒置换:将48位输入均分成长度为6的8个小组,每个小组按顺序进入相应的S盒各得到4位输出,返回合并后的32位结果。'''
result = []
for i in range(0, 8):
temp = text[i * 6:i * 6 + 6]
row = int(str(temp[0]) + str(temp[-1]), 2)
column = int(str(temp[1]) + str(temp[2]) + str(temp[3]) + str(temp[4]), 2)
letter = S_BOX[i][row][column]
result.append(dex2bin4(letter))
return [int(x) for x in ''.join(result)]
def PBoxPermutation(text):
'''P-盒置换:将32位输入按 P 规则置换后返回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]
return [text[P[i] - 1] for i in range(32)]
def xor(m, n):
'''对两个序列进行各位异或操作,并返回所得结果。'''
return [a ^ b for a, b in zip(m, n)]
def char2bin(char):
'''
返回一个(ASCII)字符的8位二进制表示。
如:'A' -> '01000001'。
'''
b = bin(ord(char)).replace('0b', '')
space = 8 - len(b)
return '0' * space + b
def string2bin(text):
'''
将含有16进制表示的字符串转化成包含64位二进制数字的列表。
'''
temp = ["{:0>4b}".format(int(char, 16)) for char in text]
temp = [int(number) for number in "".join(temp)]
return temp
def bin2string(text):
'''
将二进制数字的列表以4位为一组转化成对应16进制的字符串。
'''
length = len(text)
if(length % 4):
return False
text = [str(number) for number in text] # 先将列表里的 int 类型转化为 str 类型
result = []
for i in range(length // 4):
binstring = ''.join(text[i * 4:i * 4 + 4])
result.append(hex(int(binstring, 2))[2:]) # 去除16进制中的Hex
return ''.join(result)
'''
Author: Martin
Date: 2023-11-11 21:27:11
Description:
'''
import tkinter as tk
from tkinter import scrolledtext
from DES import DES_decrypter, DES_encrypter # Assuming your DES implementation is in a file named DES.py
from tkinter import filedialog
import time
class CryptoApp:
def __init__(self, root):
self.root = root
self.root.title("DES Encryption App")
self.root.geometry("600x550")
# Set default key and IV
self.default_key = "57696C6C69616D53"
self.default_iv = "5072656E74696365"
# Input Key
self.key_label = tk.Label(root, text="Enter Key:")
self.key_entry = tk.Entry(root)
self.key_entry.insert(tk.END, self.default_key) # Set default value
self.key_label.pack()
self.key_entry.pack()
# Input IV
self.iv_label = tk.Label(root, text="Enter IV:")
self.iv_entry = tk.Entry(root)
self.iv_entry.insert(tk.END, self.default_iv) # Set default value
self.iv_label.pack()
self.iv_entry.pack()
# Encryption Mode
self.mode_label = tk.Label(root, text="Select Mode:")
self.mode_var = tk.StringVar()
self.mode_var.set("ECB")
self.mode_menu = tk.OptionMenu(root, self.mode_var, "ECB", "CBC", "CFB", "OFB")
self.mode_label.pack()
self.mode_menu.pack()
# Text Input
self.text_label = tk.Label(root, text="Enter Text:")
self.text_input = scrolledtext.ScrolledText(root, width=40, height=5)
self.text_input.insert(tk.END, "4E6574776F726B205365637572697479")
self.text_label.pack()
self.text_input.pack()
# Encrypt and Decrypt Buttons
self.encrypt_button = tk.Button(root, text="Encrypt", command=self.encrypt)
self.decrypt_button = tk.Button(root, text="Decrypt", command=self.decrypt)
self.encrypt_button.pack()
self.decrypt_button.pack()
# Output
self.output_label = tk.Label(root, text="Output:")
self.output_text = scrolledtext.ScrolledText(root, width=40, height=5)
self.output_label.pack()
self.output_text.pack()
self.encrypt_button = tk.Button(root, text="加密文档", command=self.encrypt_document)
self.encrypt_button.pack(pady=10)
self.decrypt_button = tk.Button(root, text="解密文档", command=self.decrypt_cipher)
self.decrypt_button.pack()
self.time_label = tk.Label(root, text="Time Elapsed:")
self.time_label.pack()
self.time_var = tk.StringVar()
self.time_display = tk.Label(root, textvariable=self.time_var)
self.time_display.pack()
def encrypt(self):
start_time = time.time()
key = self.key_entry.get()
mode = self.mode_var.get()
text = self.text_input.get("1.0", tk.END).strip()
iv = self.iv_entry.get()
result = ""
if mode == "ECB":
ECBcrypter = DES_encrypter(text, key, "ECB", iv)
result = ECBcrypter.ciphertext.upper()
elif mode == "CBC" :
CBCcrypter = DES_encrypter(text, key, "CBC", iv)
result = CBCcrypter.ciphertext.upper()
elif mode == "CFB":
CFBcrypter = DES_encrypter(text, key, "CFB", iv)
result = CFBcrypter.ciphertext.upper()
elif mode == "OFB":
OFBcrypter = DES_encrypter(text, key, "OFB", iv)
result = OFBcrypter.ciphertext.upper()
print("加密:" + result)
end_time = time.time()
time_elapsed = end_time - start_time
self.time_var.set(f"Time Elapsed: {time_elapsed:.4f} seconds")
self.output_text.delete("1.0", tk.END)
self.output_text.insert(tk.END, result)
def decrypt(self):
start_time = time.time()
key = self.key_entry.get()
mode = self.mode_var.get()
text = self.output_text.get("1.0", tk.END).strip()
iv = self.iv_entry.get()
print(text)
if mode == "ECB":
ECBcrypter = DES_decrypter(text, key, "ECB", iv)
result = ECBcrypter.plaintext.upper()
elif mode == "CBC":
CBCcrypter = DES_decrypter(text, key, "CBC", iv)
result = CBCcrypter.plaintext.upper()
elif mode == "CFB":
CFBcrypter = DES_decrypter(text, key, "CFB", iv)
result = CFBcrypter.plaintext.upper()
elif mode == "OFB":
OFBcrypter = DES_decrypter(text, key, "OFB", iv)
result = OFBcrypter.plaintext.upper()
end_time = time.time()
print("解密:" + result)
time_elapsed = end_time - start_time
self.time_var.set(f"Time Elapsed: {time_elapsed:.4f} seconds")
self.output_text.delete("1.0", tk.END)
self.output_text.insert(tk.END, result)
def encrypt_document(self):
file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'r') as file:
plaintext = file.read()
key = self.key_entry.get()
mode = self.mode_var.get()
iv = self.iv_entry.get()
start_time = time.time()
ECBcrypter = DES_encrypter(plaintext, key, "ECB", iv)
ciphertext = ECBcrypter.ciphertext.upper()
self.text_input.delete("1.0", tk.END)
self.text_input.insert(tk.END, ciphertext)
print(ciphertext)
end_time = time.time()
time_elapsed = end_time - start_time
self.time_var.set(f"Time Elapsed: {time_elapsed:.4f} seconds")
# Save the ciphertext to a new txt file
save_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
if save_path:
with open(save_path, 'w') as save_file:
save_file.write(ciphertext)
print(f"Ciphertext saved to: {save_path}")
def decrypt_cipher(self):
start_time = time.time()
file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'r') as file:
plaintext = file.read()
key = self.key_entry.get()
mode = self.mode_var.get()
iv = self.iv_entry.get()
start_time = time.time()
ECBcrypter = DES_decrypter(plaintext, key, "ECB", iv)
result = ECBcrypter.plaintext.upper()
self.text_input.delete("1.0", tk.END)
self.text_input.insert(tk.END, result)
print(result)
end_time = time.time()
time_elapsed = end_time - start_time
self.time_var.set(f"Time Elapsed: {time_elapsed:.4f} seconds")
# Save the ciphertext to a new txt file
save_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
if save_path:
with open(save_path, 'w') as save_file:
save_file.write(result)
print(f"Ciphertext saved to: {save_path}")
if __name__ == '__main__':
root = tk.Tk()
app = CryptoApp(root)
root.mainloop()
'''
Author: Martin
Date: 2023-11-11 21:22:12
Description:
'''
from DES import DES_decrypter, DES_encrypter
import re
import time
import os
from operations import bin2string
global key, iv, plaintext
key = "57696C6C69616D53"
iv = "5072656E74696365"
plaintext = "4E6574776F726B20536563757269747922"
def test1():
"""验证正确加密实验
从des_plain.txt中读取明文通过4种加密方式加密后写入des_cipher.txt中
"""
# ECBcrypter = DES_encrypter(plaintext, key, "ECB", iv)
# cipher_ECB = ECBcrypter.ciphertext.upper()
CBCcrypter = DES_encrypter(plaintext, key, "CBC", iv)
cipher_CBC = CBCcrypter.ciphertext.upper()
# CFBcrypter = DES_encrypter(plaintext, key, "CFB", iv)
# cipher_CFB = CFBcrypter.ciphertext.upper()
# OFBcrypter = DES_encrypter(plaintext, key, "OFB", iv)
# cipher_OFB = OFBcrypter.ciphertext.upper()
print("加密结果:"+cipher_CBC)
def test2():
"""验证正确解密实验
"""
ECB_cipher = "958920B1358EF1972B9EE4548DC08E8A"
CBC_cipher = "5EB15B91506B9AE7CEB65954AE115E03"
CFB_cipher = "F70F01584ACF4D966ADC143EB240C962"
OFB_cipher = "F7B0FFCDC0B9BBA76092B929D769417A"
ECBcrypter = DES_decrypter(ECB_cipher, key, "ECB", iv)
plaintext_ECB = ECBcrypter.plaintext.upper()
CBCcrypter = DES_decrypter(CBC_cipher, key, "CBC", iv)
plaintext_CBC = CBCcrypter.plaintext.upper()
CFBcrypter = DES_decrypter(CFB_cipher, key, "CFB", iv)
plaintext_CFB = CFBcrypter.plaintext.upper()
OFBcrypter = DES_decrypter(OFB_cipher, key, "OFB", iv)
plaintext_OFB = OFBcrypter.plaintext.upper()
print("解密结果:"+plaintext_CBC)
from Crypto.Cipher import DES
if __name__ == "__main__":
print("明文结果:"+plaintext)
test1()
test2()