首页 > 编程 > Python > 正文

DES加密解密算法之python实现版(图文并茂)

2020-01-04 13:54:42
字体:
来源:转载
供稿:网友

一、DSEpython/301158.html">算法背景介绍

1. DES的采用
1979年,美国银行协会批准使用
1980年,美国国家标准局(ANSI)赞同DES作为私人使用的标准,称之为DEA(ANSI X.392)
1983年,国际化标准组织ISO赞同DES作为国际标准,称之为DEA-1
该标准规定每五年审查一次,计划十年后采用新标准
最近的一次评估是在1994年1月,已决定1998年12月以后,DES将不再作为联邦加密标准。

2.DES算法特点

1) 分组加密算法:

以64位为分组。64位一组的明文从算法一端输入,64位密文从另一端输出。

2) 对称算法:

加密和解密用同一密钥。

3) 有效密钥长度为56位。

密钥通常表示为64位数,但每个第8位用作奇偶校验,可以忽略。输入的64bit秘钥只有56bit作为有效位

二、DES算法描述

1、DES算法加密流程的文字描述

DES对64位的明文分组进行操作。通过一个初始置换,将明文分组分成左半部分和右半部分,各32位长。然后进行16轮完全相同的运算,这些运算被称为函数f,在运算过程中数据与密钥结合。经过16轮后,左、右半部分合在一起,经过一个末置换(初始置换的逆置换),这样该算法就完成了。

二、DES算法加密流程的图形描述

DES,加密,解密,算法,python

                              图一

DES,加密,解密,算法,python

图二

三、具体参数解释

1、IP置换和IP逆置换

IP置换作用于进行16轮f函数作用之前,IP逆置换作用于16轮f函数作用之后。IP置换和IP逆置换表如下图所示:

DES,加密,解密,算法,python

图三

该表的含义解释:例如IP置换表中的第一行第一列的数值为58,就代表将明文的第58位替换到第一位,例如明文初始的第58位是1,第1位是0,第39位是0,根据上表替换后的64位待加密文本为:第一位是1,第58位是0。之后提到的置换表也是这个意思。

2、f函数

经过初始置换后,进行16轮完全相同的运算。这些运算被称为f,在运算过程中数据与密钥结合。f函数作用于每轮的key值和每轮的待加密文本的右半部分,即Ki,Ri

f函数作用于每轮的key值和每轮的待加密文本的右半部分,即Ki,Ri

DES,加密,解密,算法,python

                                                             图四

函数¦的输出经过一个异或运算,和左半部分结合,其结果成为新的右半部分,原来的右半部分成为新的左半部分。

DES,加密,解密,算法,python

                                                                                  图五

3、扩展置换,扩展置换将32位的R部分,扩展为48位

扩展表如图所示:

DES,加密,解密,算法,python

                                                  图六

4、S盒替换,S盒替换将扩展替换后与ki(第i轮KEY值)异或后的结果压缩为32位,每6位与一个S盒运算,运算后压缩为4位,共有八个S盒,分为S1,S2......S8。具体如下图所示

DES,加密,解密,算法,python

                                                                                              图七

S盒介绍,以第六个S盒,S6为例

DES,加密,解密,算法,python

                                                                                                                                       图八

设入的六位为b1,b2,b3,b4,b5,b6,b1、b6位组合得到列号,b2,b3,b4,b5组合得到行号。具体实现看底下的代码。确定行号和列好后将6位替换为4位数据,数据段具体值即为行列相交处的值,例如3行4列即为5,5的二进制码位1001,将原来的6位替换为4位即1001

4、P盒替换

P盒替换将S盒替换之后的结果进行一次位置替换,替换表如图所示:DES,加密,解密,算法,python

                                                                                                  图九

5 最后讲一下重头戏——16轮秘钥生成

先上个图

DES,加密,解密,算法,python

                                                                                                    图10

图中的置换选择1和置换选择2跟之前将的置换选择原理是一样的,在代码中你能看到置换表

这里也给出来吧

DES,加密,解密,算法,python

                                                         图11

C0,D0指的是将56位(注位都是指的bit)秘钥分为左右两部分,C0代表左半部分,D0是右半部分。循环左移指的是将bit位循环左移,移除的位补到末尾,l例如100010循环左移一位之后位000101

每轮秘钥生成的时候循环左移的次数都不一样,具体如下表

DES,加密,解密,算法,python

                                                                                   图12

四、以上都是文字加图表描述,下面直接上代码,代码我都加了详细的备注,大家结合上面的说明一定能读懂滴。有点长,大家细心看

#writter:liuyang@BUAASoftwareDepartment#date:2014/05/14#function:DEC加密、解密算法#contact me:734056968@qq.com#IP置换表IP_table=[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置换表_IP_table=[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]#S盒中的S1盒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]#S盒中的S2盒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]#S盒中的S3盒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]#S盒中的S4盒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]#S盒中的S5盒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]#S盒中的S6盒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]#S盒中的S7盒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]#S盒中的S8盒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=[S1,S2,S3,S4,S5,S6,S7,S8]#P盒P_table=[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,不考虑每字节的第8位,将64位密钥减至56位。然后进行一次密钥置换。yasuo1_table=[ 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,用于将循环左移和右移后的56bit密钥压缩为48bityasuo2_table=[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]#用于对数据进行扩展置换,将32bit数据扩展为48bitextend_table=[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]#将字符转换为对应的Unicode码,中文用2个字节表示def char2unicode_ascii(intext,length):    outtext=[]    for i in range(length):        outtext.append(ord(intext[i]))    return outtext#将Unicode码转为bit    def unicode2bit(intext,length):    outbit=[]    for i in range(length*16):        outbit.append((intext[int(i/16)]>>(i%16))&1)#一次左移一bit    return outbit#将8位ASCII码转为bit    def byte2bit(inchar,length):    outbit=[]    for i in range(length*8):        outbit.append((inchar[int(i/8)]>>(i%8))&1)#一次左移一bit    return outbit#将bit转为Unicode码def bit2unicode(inbit,length):    out=[]    temp=0    for i in range(length):        temp=temp|(inbit[i]<<(i%16))        if i%16==15:                        out.append(temp)            temp=0    return out#将bit转为ascii 码def bit2byte(inbit,length):    out=[]    temp=0    for i in range(length):        temp=temp|(inbit[i]<<(i%8))        if i%8==7:                        out.append(temp)            temp=0    return out#将unicode码转为字符(中文或英文)def unicode2char(inbyte,length):    out=""    for i in range(length):        out=out+chr(inbyte[i])    return out#生成每一轮的keydef createKeys(inkeys):    keyResult=[]    asciikey=char2unicode_ascii(inkeys,len(inkeys))    keyinit=byte2bit(asciikey,len(asciikey))#    print("keyinit=",end='')#    print(keyinit)    #初始化列表key0,key1    key0=[0 for i in range(56)]    key1=[0 for i in range(48)]    #进行密码压缩置换1,将64位密码压缩为56位    for i in range(56):        key0[i]=keyinit[yasuo1_table[i]-1]            #进行16轮的密码生成            for i in range(16):        #---------确定左移的次数----------        if (i==0 or i==1 or i==8 or i==15):            moveStep=1        else:            moveStep=2        #------------------------------                    #--------分两部分,每28bit位一部分,进行循环左移------------            for j in range(moveStep):            for k in range(8):                temp=key0[k*7]                for m in range(7*k,7*k+6):                    key0[m]=key0[m+1]                key0[k*7+6]=temp            temp=key0[0]            for k in range(27):                key0[k]=key0[k+1]            key0[27]=temp            temp=key0[28]            for k in  range(28,55):                key0[k]=key0[k+1]            key0[55]=temp        #-----------------------------------------------------        #------------对56位密钥进行压缩置换,压缩为48位-------------        for k in range(48):            key1[k]=key0[yasuo2_table[k]-1]             keyResult.extend(key1)                #------------------------------------------------------            return keyResultdef DES(text,key,optionType):    keyResult=createKeys(key)    finalTextOfBit=[0 for i in range(64)]    finalTextOfUnicode=[0 for i in range(4)]#    print(keyResult)                 if optionType==0:#选择的操作类型为加密                tempText=[0 for i in range(64)]#用于临时盛放IP逆置换之前,将L部分和R部分合并成64位的结果        extendR=[0 for i in range(48)]#用于盛放R部分的扩展结果        unicodeText=char2unicode_ascii(text,len(text))#        print(unicodeText)        bitText=unicode2bit(unicodeText,len(unicodeText))#        print(bitText)                initTrans=[0 for i in range(64)]#初始化,用于存放IP置换后的结果                #------------------进行初始IP置换---------------        for i in range(64):            initTrans[i]=bitText[IP_table[i]-1]        #将64位明文分为左右两部分        L=[initTrans[i] for i in range(32)]        R=[initTrans[i] for i in range(32,64)]                        #开始进行16轮运算                      for i in range(16):            tempR=R #用于临时盛放R                        #-----------进行扩展,将32位扩展为48位--------            for j in range(48):                extendR[j]=R[extend_table[j]-1] #           print(len(keyResult))                keyi=[keyResult[j] for j in range(i*48,i*48+48)]            #----------与key值进行异或运算----------------            XORResult=[0 for j in range(48)]            for j in range(48):                if keyi[j]!=extendR[j]:                    XORResult[j]=1                        SResult=[0 for k in range(32)]             #---------开始进行S盒替换-------------------                      for k in range(8):                row=XORResult[k*6]*2+XORResult[k*6+5]                column=XORResult[k*6+1]*8+XORResult[k*6+2]*4+XORResult[k*6+3]*2+XORResult[k*6+4]                temp=S[k][row*16+column]                for m in range(4):                    SResult[k*4+m]=(temp>>m)&1             #-----------------------------------------            PResult=[0 for k in range(32)]            #--------------开始进行P盒置换----------------            for k in range(32):                PResult[k]=SResult[P_table[k]-1]            #------------------------------------------            #--------------与L部分的数据进行异或------------            XORWithL=[0 for k in range(32)]            for k in range(32):                if L[k]!=PResult[k]:                    XORWithL[k]=1            #----------------------------------------------            #-------------将临时保存的R部分值,即tempR复制给L------            L=tempR            R=XORWithL                    #----交换左右两部分------        L,R=R,L                #-----合并为一部分        tempText=L        tempText.extend(R)        #-----------IP逆置换--------        for k in range(64):            finalTextOfBit[k]=tempText[_IP_table[k]-1]        finalTextOfUnicode=bit2byte(finalTextOfBit,len(finalTextOfBit))#        print(finalTextOfUnicode)        finalTextOfChar=unicode2char(finalTextOfUnicode,len(finalTextOfUnicode))#        print(finalTextOfChar)        return finalTextOfChar    else:#选择的操作类型为解密        tempText=[0 for i in range(64)]#用于临时盛放IP逆置换之前,将L部分和R部分合并成64位的结果        extendR=[0 for i in range(48)]#用于盛放R部分的扩展结果        unicodeText=char2unicode_ascii(text,len(text))#        print(unicodeText)        bitText=byte2bit(unicodeText,len(unicodeText))#        print(bitText)                initTrans=[0 for i in range(64)]#初始化,用于存放IP置换后的结果                #------------------进行初始IP置换---------------        for i in range(64):            initTrans[i]=bitText[IP_table[i]-1]        #将64位明文分为左右两部分        L=[initTrans[i] for i in range(32)]        R=[initTrans[i] for i in range(32,64)]                #-----------------开始16轮的循环-----------------        for i in range(15,-1,-1):            tempR=R #用于临时盛放R                        #-----------进行扩展,将32位扩展为48位--------            for j in range(48):                extendR[j]=R[extend_table[j]-1]                            keyi=[keyResult[j] for j in range(i*48,i*48+48)]            #----------与key值进行异或运算----------------            XORResult=[0 for j in range(48)]            for j in range(48):                if keyi[j]!=extendR[j]:                    XORResult[j]=1                        SResult=[0 for k in range(32)]             #---------开始进行S盒替换-------------------                      for k in range(8):                row=XORResult[k*6]*2+XORResult[k*6+5]                column=XORResult[k*6+1]*8+XORResult[k*6+2]*4+XORResult[k*6+3]*2+XORResult[k*6+4]                temp=S[k][row*16+column]                for m in range(4):                    SResult[k*4+m]=(temp>>m)&1             #-----------------------------------------            PResult=[0 for k in range(32)]            #--------------开始进行P盒置换----------------            for k in range(32):                PResult[k]=SResult[P_table[k]-1]            #------------------------------------------            #--------------与L部分的数据进行异或------------            XORWithL=[0 for k in range(32)]            for k in range(32):                if L[k]!=PResult[k]:                    XORWithL[k]=1            #----------------------------------------------            #-------------将临时保存的R部分值,即tempR复制给L------            L=tempR            R=XORWithL                    #----交换左右两部分------        L,R=R,L                #-----合并为一部分        tempText=L        tempText.extend(R)        #-----------IP逆置换--------        for k in range(64):            finalTextOfBit[k]=tempText[_IP_table[k]-1]        finalTextOfUnicode=bit2unicode(finalTextOfBit,len(finalTextOfBit))#        print(finalTextOfUnicode)        finalTextOfChar=unicode2char(finalTextOfUnicode,len(finalTextOfUnicode))#        print(finalTextOfChar)        return finalTextOfChar          def main():        text=input("请输入要操作的文本:  ")    print(" ".join(["输入的文本时",text]))    optionType=input("请选择是进行加密还是解密,加密输入0,解密输入1:  ")    while(not(optionType=='0' or optionType=='1')):        print("Wrong!!!选择的操作类型只能是0或者是1")        optionType=input("请选择是进行加密还是解密,加密输入0,解密输入1:  ")    length=len(text)    Result=""    if optionType=='0':#        f=open('D:/encyptText.txt','w') #----------若输入文本的长度不是4的整数倍,即不是64字节的整数倍,用空格补全(此处为了加密中文,用的是unicode编码,即用16字节表示一个字符)-------        text=text+(length%4)*" "        length=len(text)        key=input("请输入8位加密密码: ")                while(len(key)!=8):            print("wrong!!请输入8位密码")            key=input("请输入8位加密密码: ")                    print("加密后的文本:",end=" ")                    for i in range(int(length/4)):            tempText=[text[j] for j in range(i*4,i*4+4)]            Result="".join([Result,DES(tempText,key,int(optionType))])#            f.write(Result)        print(Result)     if optionType=='1': #----------若输入文本的长度不是8的整数倍,即不是64字节的整数倍,用空格补全(此处解密出来的密文用的是每8bit转换为一个ascii码,所以生成的八位表示的字符)-------#        text=text+(length%8)*" "        length=len(text)         key=input("请输入8位解密密码: ")        while(len(key)!=8):            print("wrong!!请输入8位密码")            key=input("请输入8位解密密码: ")                    print("解密后的文本:",end=" ")        for i in range(int(length/8)):            tempText=[text[j] for j in range(i*8,i*8+8)]            Result="".join([Result,DES(tempText,key,int(optionType))])        print(Result)

六、运行截图

DES,加密,解密,算法,python

图13

七、后记

1、要用于具体项目的话,要把编码格式弄清楚,看你项目中的编码格式是什么,unicode,utf-8,gdb等否则会出错

2、文本输入的时候不能有换行,如果需要换行加一下转换符,调一调


注:相关教程知识阅读请移步到python教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表