DES对称密码设计

本文详细介绍了DES加密算法的工作原理,包括初始换位、f函数、逆初始置换等核心步骤,并展示了如何设计一个Python程序来实现DES的加密和解密过程。实验结果显示,该程序能够正确地对给定的明文和密钥进行加解密,验证了DES算法的正确性。
摘要由CSDN通过智能技术生成

DES介绍和分析:

  DES算法将明文分成64位大小的众多数据块,即分组长度为64位。同时用56位密钥对64位明文信息加密,最终形成64位的密文。如果明文长度不足64位,则将其扩展为64位(如补零等方法)。
  具体加密过程首先是将输入的数据进行初始换位(IP),即将明文M中数据的排列顺序按一定的规则重新排列,生成新的数据序列,以打乱原来的次序。然后将变换后的数据平分成左右两部分,左边记为L0,右边记为R0,然后对R0实行在子密钥(由加密密钥产生)控制下的变换f,结果记为f(R0,K1),再与L0做逐位异或运算,其结果记为R1,R0则作为下一轮的L1。如此循环16轮,最后得到L16、R16,再对L16、R16实行逆初始置换IP-1,即可得到加密数据。解密过程与此类似,不同之处仅在于子密钥的使用顺序正好相反。
DES全部16轮的加密过程如图2.1所示。
在这里插入图片描述
DES的加密算法包括3个基本函数。
1.初始换位(IP)
  它的作用是把输入的64位数据块的排列顺序打乱,每位数据按照下面换位规则重新组合,即将第58位换到第1位,第50位换到第2位,……,依次类推。重组后的64位输出分为L0、R0(左、右)两部分,每部分分别为32位。
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
R0和K1经过f(R0,K1)变换后的输出结果,再和L0进行异或运算,输出结果做为R1,R0则赋给L1。L1和Rl同样再做类似运算生成L2和R2,……,经过16次运算后生成L16和R16。
2.f函数
  f函数是多个置换函数和替代函数的组合函数,它将32位比特的输入变换为32位的输出,如图2.2所示。Ri经过扩展运算E变换后扩展为48位的E(Ri),与Ki+1进行异或运算后输出的结果分成8组,每组6比特的并联B,B=BlB2B3B4B5B6B7B8,再经过8个S盒的选择压缩运算转换为4位,8个4位合并为32位后再经过P变换输出为32位的f(Ri,Ki+1)。其中,扩展运算E与置换P主要作用是增加算法的扩散效果。
在这里插入图片描述
3.逆初始置换函数IP-1
它将L16和R16作为输入,进行逆初始换位得到密文输出。逆初始换位是初始换位的逆运算,换位规则如下所列:
在这里插入图片描述

子密钥生成:
DES的加密算法中除了上面介绍的3个基本函数,还有一个非常重要的功能模块,即子密钥的生成模块,具体子密钥的产生流程如图2.3所示。
在这里插入图片描述
输入的初始密钥值为64位,但DES算法规定,其中第8、16、……、64位是奇偶校验位,不参与DES运算。所以,实际可用位数只有56位,经过缩小选择换位表1(表2-2)即密钥置换PC-1的变换后,初始密钥的位数由64位变成了56位,将其平分为两部分C0、D0,然后分别进行第1次循环左移,得到Cl、Dl,将Cl(28位)、Dl(28位)合并后得到56位的输出结果,再经过缩小选择换位表2(表2-3)即密钥置换PC-2,从而得到了密钥K1(48位)。依次类推,便可得到K2、……、K16。需要注意的是,16次循环左移对应的左移位数要依据表2-1的规则进行。

  表2-1 左移位数规则
在这里插入图片描述
  表2-2缩小选择换位表1
在这里插入图片描述
  表2-3缩小选择换位表
在这里插入图片描述

设计一个程序可以利用DES算法进行加密和解密。
验证:假设明文为:123456ABCD132536,密钥为:AABB09182736CCDD
密文为:C0B7A8D05F3A829C
加密验证过程数据如下图:

在这里插入图片描述

实验代码为:

# -*- coding: UTF-8 -*-
import time
"""
    DES算法实现加解密
    @author WQ
    @time 2020/12/2
"""
class DES():
    """
        DES:加解密模块
    """
    def __init__(self):
        pass

    def extract_keystream(self,model,keys):
        """
        args{
            model:模式1密钥为十六进制形式,模式2密钥为字符串形式
        }
        """
        self.original_keystream=''
        self.keys=keys
        if model==1:
            for c in self.keys:
                if c >= '0' and c <= '9':
                    c=ord(c)-48
                    self.original_keystream+= bin(c).replace('0b','').zfill(4)#单个字符不足8位补0
                elif c >='A' and c <= 'F':
                    c=ord(c)-55
                    self.original_keystream+= bin(c).replace('0b','').zfill(4)#单个字符不足8位补0
        elif model==2:
            for c in self.keys:
                self.original_keystream+= bin(ord(c)).replace('0b','').zfill(8)
        else:
            pass
        
        if len(self.original_keystream)>64:
            self.original_keystream=self.original_keystream[:64]

        for i in range(64-len(self.original_keystream)):#秘钥不足64位,用0补全
            self.original_keystream+='0'
        
        """
        #64位密钥剔除奇偶校验位得到56位密钥
        newkeystream=''
        i=1
        for k in keystream:
            if(i%8!=0):
                newkeystream=newkeystream+k
            i=i+1
        self.keystream=newkeystream #剔除后的原始56位密钥
        """

    def reverse_function1(self):
        """
        args{
            密钥置换1
            self.keystream:56位原始密钥
        }
        """#置换选择表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]]
        self.reverse1=[]
        #print(len(self.original_keystream))
        for i in PC_1:
            for j in i:
                self.reverse1.append(self.original_keystream[j-1])
        return self.reverse1

    def reverse_function2(self):
        """
        args{
            密钥置换2

        }
        """#置换选择表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]
        self.reverse2=self.reverse2_0x=[]#置换2后的的子秘钥列表
        cyc_keystream=[]#移位后的子秘钥列表
        left=self.reverse1[:28]#置换1后左半部
        right=self.reverse1[28:]#置换1后右半部

        cyc_List=[1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]#移位数列表
        for i in cyc_List:
            left=self.cycleLeft(left,i)
            right=self.cycleLeft(right,i)
            cyc_keystream.append(left+right)#移位后的子秘钥列表
            """
            for k in range(0,28):
                left[k]=newleft[k]
                right[k]=newright[k]
            """
        end_keystream=[]#置换选择2后的最终子密钥列表
        for key in cyc_keystream: #逐个取每轮的子密钥
            temp=[]
            for i in PC_2:
                temp.append(key[i-1])
            end_keystream.append(temp)
        temp=[]
        #print(len(end_keystream),len(end_keystream[0]))
        for keys in end_keystream:#提取密钥为字符串
            str1=''
            for keystr in keys:
                str1+=keystr
            temp.append(str1)
        #print(temp)
        self.reverse2=temp

    def strToBin(self,string):
        """
        args{
            string:二进制字符串转数值
        }
        """
        k=len(string)-1
        values=0
        for i in string:
            values=int(i)*pow(2,k)+values
            k=k-1
        return values

    def cycleLeft(self,keyList,cycleNum):
        """
        args{
            keyList:需要移位的密钥列表
            len:移位位数
        }
        """
        return keyList[cycleNum:]+keyList[:cycleNum]
    
    def get_plainGroup(self,model,plainText):
        """
        获取明文并按64位进行分组
        args{
            plainText:明文字符串
            model:模式选择,1十六进制形式,2字符串形式
        }
        """
        plainStr=''
        self.plainText=[]
        if model==1:
            for c in plainText:
                if c >= '0' and c <= '9':
                    c=ord(c)-48
                    plainStr+= bin(c).replace('0b','').zfill(4)#单个字符不足4位补0
                elif c >='A' and c <= 'F':
                    c=ord(c)-55
                    plainStr+= bin(c).replace('0b','').zfill(4)#单个字符不足4位补0
        elif model==2:
            for c in plainText:
                plainStr+= bin(ord(c)).replace('0b','').zfill(8)
        #print('明文长度:',len(plainStr))
        #不足64位用0补齐
        if len(plainStr) <= 64:
            for i in range(64-len(plainStr)):
                plainStr+='0'
            self.plainText.append(plainStr)
        else:   #大于64位则分组
            groupNum=len(plainStr)//64   #每组64位,确定要分多少组
            if len(plainStr)%64 !=0:
                #print(groupNum)
                groupNum+=1

            for i in range(groupNum*64-len(plainStr)):
                plainStr+='0'
            k=0 #用于定位分组
            for n in range(groupNum):
                temp=''
                for i in range(64):
                    temp+=plainStr[k+i]
                k+=64
                self.plainText.append(temp)
        #print('明文二进制:',self.plainText)
    
    def initReverse(self):
        #明文进行初始置换
        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]
        self.IPreverse=[]
        for i in self.plainText:
            temp=''
            for j in IP:
                temp+=i[j-1]
            self.IPreverse.append(temp)
        #print('初始置换后:',self.IPreverse)

    def Encrypt_Decrypt(self,model=0):
        """
        轮加密
        args{
            model:为0时加密;为1时解密
        }
        """
        if model==0:
            self.key=self.reverse2
        elif model==1:
            self.key=self.reverse2[::-1]
        print('明文:',self.covertHex(self.plainText[0]))
        print('初始置换后:',self.covertHex(self.IPreverse[0]))
        print('轮序(i)  '+'L(i)     ' +'R(i)     '+'key(i)')
        self.cipherText=[]
        for i in self.IPreverse:
            R=[]
            count=0 #计数当前加密轮次
            left=i[:32]
            right=i[32:]
            R.append(right) #用于更新left
            for key in self.key:
                right=self.extend_reverse(right)
                xor_1=xor_2=''
                for j in range(0,len(right),8):#右部扩展后与密钥进行异或
                    x=self.strToBin(right[j:j+8])
                    y=self.strToBin(key[j:j+8])
                    z=x^y
                    xor_1+=bin(z).replace('0b','').zfill(8)
                temp=self.instead_choose(xor_1) #s盒处理进行压缩为32位
                temp=self.P_revrese(temp)   #p置换
                #左部与处理后的右部进行异或输出
                for j in range(0,len(temp),8):
                    x=self.strToBin(temp[j:j+8])
                    y=self.strToBin(left[j:j+8])
                    z=x^y
                    xor_2+=bin(z).replace('0b','').zfill(8)
                R.append(xor_2)
                right=xor_2 #下一轮加密,输出作为下一轮右部输入
                left=R[count]
                print('轮序 '+str(count+1),self.covertHex(left),self.covertHex(right),self.covertHex(key))
                count+=1    #计数当前加密轮次

            print('左右交换后:',self.covertHex(right),self.covertHex(left))
            print('左右部分合在一起',self.covertHex(right)+self.covertHex(left))
            ciphertext=right+left   #左右交换
            ciphertext=self.reInitReverse(ciphertext) #逆初始置换
            str1=self.covertHex(ciphertext) #将密文转为十六进制
            print('逆初始置换后(密文):',str1)
            self.cipherText.append(str1)
        text=''
        for i in range(len(self.cipherText)):
            text+=self.cipherText[i]    
        print("密文为:",text)       

    def extend_reverse(self,str1):
        """
        str:待扩展置换的明文字符串(右半部32位)
        扩展为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]
        temp=''
        for i in E:
            temp+=str1[i-1]
        return temp

    def instead_choose(self,strBit):
        """
        代换选择,将右部和密钥异或后的值48位通过s盒压缩为32位
        strBit:48位比特流
        """
        S =  [[[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]]]
        sbox_narrow=''
        for i in range(0,len(strBit),6):
            S_index=temp=''
            temp=strBit[i:i+6]
            S_index=temp[0]+temp[5]
            row=self.strToBin(S_index)
            column=self.strToBin(temp[1:5])
            sbox_narrow+=bin(S[i//6][row][column]).replace('0b','').zfill(4)
        
        return sbox_narrow

    def P_revrese(self,str1):
        """
        s盒处理后的p置换
        str1:s盒处理后的32位bit
        """
        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]
        temp=''
        for i in P:
            temp+=str1[i-1]
        return temp

    def reInitReverse(self,str):
        """
        逆初始置换IP-1
        """
        IP_re= [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]
        temp=''
        for i in IP_re:
            temp+=str[i-1]
        return temp

    def covertHex(self,string):
        """
        string:待转换的二进制比特流
        返回十六进制字符串
        """
        str1=''
        for c in range(0,len(string),4):
            x=hex(self.strToBin(string[c:c+4]))
            str1+=str(x).replace('0x','')
        return str1.upper() 

if __name__ == "__main__":
    start=time.time()
    test=DES()
    test.extract_keystream(1,"AABB09182736CCDD")#获取密钥
    test.reverse_function1()#密钥置换1
    test.reverse_function2()#密钥置换2
    print('***************加密***************')
    test.get_plainGroup(1,"123456ABCD132536456789")#获取明文
    test.initReverse()#初始置换
    test.Encrypt_Decrypt()#加密
    print('***************解密***************')
    test.get_plainGroup(1,"C0B7A8D05F3A829CEDED4AC8BBEE63AF")#获取密文E157B8BD50A089F1F78EC819B8149635688D54C5FE717AD9
    test.initReverse()#初始置换
    test.Encrypt_Decrypt(1)#解密
    #time.sleep(5)
    end=time.time()
    print('程序运行时间为:{}s'.format(end-start))

运行结果为:
在这里插入图片描述在这里插入图片描述

小结:实验结果与预期一致;通过实验对DES对称密码的加密原理和流程有了清晰的了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值