实验二 DES密码算法的设计与实现

✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆
🔥系列专栏 :简单外包单
📃新人博主 :欢迎点赞收藏关注,会回访!
💬舞台再大,你不上台,永远是个观众。平台再好,你不参与,永远是局外人。能力再大,你不行动,只能看别人成功!没有人会关心你付出过多少努力,撑得累不累,摔得痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷。


实验二 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进制。

  1. def cipher(message, key, mode=‘encrypt’):
  2. subkeys = CreateSubKeys(key) **if** mode == 'encrypt' **else** CreateSubKeys(key)[::-1]  # 顺序相反取密钥  
    
  3. text = IpPermutation(message)  
    
  4. **for** i **in** range(16):  
    
  5.     l, r = text[:32], text[32:]  
    
  6.     r_extend = ExtendPermutation(r)  
    
  7.     xor1 = xor(r_extend, subkeys[i])  
    
  8.     s_box_result = SBoxPermutation(xor1)  
    
  9.     p_box_result = PBoxPermutation(s_box_result)  
    
  10.     xor2 = xor(l, p_box_result)  
    
  11.     text = r + xor2  
    
  12. text = text[32:] + text[:32]  
    
  13. **return** InverseIpPermutation(text)  
    

fill(message): 这个函数用于对消息进行填充,以确保字符分组长度为64的整数倍。如果消息长度不是64的整数倍,就用默认字符 “0” 补全到下一个64位的整数倍。

  1. def fill(message):
  2. ''''' 
    
  3. 填充函数,若字符分组长度不为16的倍数,使用默认字符“0”补全为16的整数倍。 
    
  4. '''  
    
  5. **try**:  
    
  6.     mod = len(message) % 64  
    
  7.     space = 64 - mod  
    
  8.     **while**(space > 0):  
    
  9.         message = message.append("0")  
    
  10.         space -= 1  
    
  11.     **return** message  
    
  12. **except** AttributeError:  
    
  13.     **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: 输出反馈模式的解密操作。
核心代码:

  1. dex2bin4 函数:将十进制数(不超过15)转换为4位二进制字符串。
    使用bin函数获取二进制字符串表示,去除前缀"0b"。
    补零使其长度为4。
    dex2bin8 函数:将十进制数转换为8位二进制字符串。
    使用bin函数获取二进制字符串表示,去除前缀"0b"。
    补零使其长度为8。

  2. def dex2bin4(dex):

  3. ''''' 
    
  4. 将(不超过15的)十进制数转化成4位二进制字符串。 
    
  5. 如:13 -> '1101'。 
    
  6. '''  
    
  7. temp = bin(dex).replace('0b', '')  
    
  8. length = len(temp)  
    
  9. addzero = '0' * (4 - length)  # 不足四位的在前面补0  
    
  10. **return** addzero + temp  
    
  11. SBoxPermutation 函数:
    对48位输入进行S-盒置换。
    将48位分成8个6位小组,每个小组进入相应的S盒。
    获取S盒中的值,转换为4位二进制表示。
    将所有小组得到的32位结果合并。

  12. def SBoxPermutation(text):

  13. '''''S-盒置换:将48位输入均分成长度为6的8个小组,每个小组按顺序进入相应的S盒各得到4位输出,返回合并后的32位结果。'''  
    
  14. result = []  
    
  15. **for** i **in** range(0, 8):  
    
  16.     temp = text[i * 6:i * 6 + 6]  
    
  17.     row = int(str(temp[0]) + str(temp[-1]), 2)  
    
  18.     column = int(str(temp[1]) + str(temp[2]) + str(temp[3]) + str(temp[4]), 2)  
    
  19.     letter = S_BOX[i][row][column]  
    
  20.     result.append(dex2bin4(letter))  
    
  21. **return** [int(x) **for** x **in** ''.join(result)]  
    
  22. PBoxPermutation 函数:
    对32位输入按P-盒规则置换。
    使用P盒置换规则进行置换。

  23. def PBoxPermutation(text):

  24. '''''P-盒置换:将32位输入按 P 规则置换后返回32位结果。'''  
    
  25. P = [16, 7, 20, 21, 29, 12, 28, 17,  
    
  26.      1, 15, 23, 26, 5, 18, 31, 10,  
    
  27.      2, 8, 24, 14, 32, 27, 3, 9,  
    
  28.      19, 13, 30, 6, 22, 11, 4, 25]  
    
  29. **return** [text[P[i] - 1] **for** i **in** range(32)]  
    
  30. xor 函数:
    对两个序列进行各位异或操作。
    返回异或结果。

  31. def xor(m, n):

  32. '''''对两个序列进行各位异或操作,并返回所得结果。'''  
    
  33. **return** [a ^ b **for** a, b **in** zip(m, n)]  
    
  34. char2bin 函数:
    返回ASCII字符的8位二进制表示。
    使用ord函数获取字符ASCII码,再使用bin函数获取二进制表示。
    补零使其长度为8。

  35. def char2bin(char):

  36. ''''' 
    
  37. 返回一个(ASCII)字符的8位二进制表示。 
    
  38. 如:'A' -> '01000001'。 
    
  39. '''  
    
  40. b = bin(ord(char)).replace('0b', '')  
    
  41. space = 8 - len(b)  
    
  42. **return** '0' * space + b  
    
  43. string2bin 函数:
    将包含16进制表示的字符串转化为包含64位二进制数字的列表。
    对字符串中的每个16进制字符,使用int和bin函数转化为4位二进制字符串,再拼接在一起。
    最终将字符串表示的二进制转换为整数列表。

  44. def string2bin(text):

  45. ''''' 
    
  46. 将含有16进制表示的字符串转化成包含64位二进制数字的列表。 
    
  47. '''  
    
  48. temp = ["{:0>4b}".format(int(char, 16)) **for** char **in** text]  
    
  49. temp = [int(number) **for** number **in** "".join(temp)]  
    
  50. **return** temp  
    
  51. bin2string 函数:
    将64位二进制数字的列表以4位为一组转化为对应的16进制字符串。
    对列表中的每4个二进制数,使用join方法拼接为一个字符串。
    将每个字符串表示的16进制数字转换为整数,再转换为16进制字符串表示。

  52. def bin2string(text):

  53. ''''' 
    
  54. 将二进制数字的列表以4位为一组转化成对应16进制的字符串。 
    
  55. '''  
    
  56. length = len(text)  
    
  57. **if**(length % 4):  
    
  58.     **return** False  
    
  59. text = [str(number) **for** number **in** text]  # 先将列表里的 int 类型转化为 str 类型  
    
  60. result = []  
    
  61. **for** i **in** range(length // 4):  
    
  62.     binstring = ''.join(text[i * 4:i * 4 + 4])  
    
  63.     result.append(hex(int(binstring, 2))[2:])  # 去除16进制中的Hex  
    
  64. **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()


    

  • 21
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就你叫Martin?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值