密码加密解密(五)——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加解密过程:
在这里插入图片描述

f函数处理流程:
在这里插入图片描述

子密钥产生流程:
在这里插入图片描述

python源代码:

'''
   args = {
        name:DES加解密
        author:Lsy
        date:2020-11-18
   }
'''

#关于需要对数据处理的相关表格
#初始置换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_Inverse_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
                    ]
#选择扩展运算E(将32位扩展为48位)
E_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
           ]
# 置换运算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
           ]
# S盒
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],
]

# 关于对秘钥处理的相关表格
# 置换选择表1,对秘钥进行压缩,将64位压缩成56位
PC1_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,对秘钥进行压缩,将56位压缩成48位
PC2_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
             ]
# 循环移位位数表
left_rotations = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

#字符串转换成二进制bit串
def StringToBit(string,mode=1):
    '''
    args = {
        string:需要转换的字符串
        mode:转换模式,如果为1,则使用十六进制;如果为2,则使用unicode编码,16位,可加密中文;如果为3,使用unicode编码,8位
        返回值:
        Bit:二进制bit列表,形如[[01010.....][0020102....]],其中每个列表中有64位
    }
    '''
    Bit = []
    j = 1
    str1 = ''
    if mode==1:#十六进制模式
        for i in range(len(string)):
            n = int(string[i], 16)
            a = []
            for j in range(4):
                a.insert(0, str(n % 2))
                n = int(n / 2)
            str1 = str1+''.join(a)
            if i % 16 == 15:
                Bit.append(list(int(m) for m in str1))
                str1 = ''
        if len(string) % 16 != 0:
            str1 = str1.ljust(64, '0')
            Bit.append(list(int(m) for m in str1))
        return Bit
    elif mode==2:#unicode16位模式
        bitnum = 16
    else:#unicode8位模式
        bitnum = 8
    for i in string:
        str1+="{0:b}".format(ord(i)).zfill(bitnum)
        if j%(64/bitnum)==0:
            Bit.append(list(int(m) for m in str1))
            str1 = ''
        j +=1
    if len(string)%(64/bitnum)!=0:
        str1 = str1.ljust(64,'0')
        Bit.append(list(int(m) for m in str1))
    return Bit




#将bit换成字符串
def BitToString(Bit,mode=1):
    '''
        args = {
            Bit:需要转换的二进制字符串,形如:如[[01010.....][0020102....]],其中每个列表中有64位
            mode:转换模式,如果为1,则使用十六进制;如果为2,则使用unicode编码,16位,可加密中文;如果为3,使用unicode编码,8位
            返回值:
            Bit:二进制bit列表,形如[['0','1','0'.....]['0','0','0'....]],其中每个列表中有64位
        }
    '''
    String = ''
    if mode == 1:
        for i in Bit:
            for j in range(16):
                String += hex(
                    i[4 * j] * 8 + i[4 * j + 1] * 4 + i[4 * j + 2] * 2 + i[4 * j + 3] * 1)[
                          2:].upper()
        return String
    elif mode==2:
        bitnum = 16
    else:
        bitnum = 8
    for i in Bit:
        for j in range(int(64/bitnum)):
            str1 = i[j*bitnum:(j+1)*bitnum]
            str2 = ''
            for z in str1:
                str2 += str(z)
            String += chr(int(str2,2))
    return String

#辅助函数
def bitTTToString(i,n):
    '''
    args = {
        i:带有n为bit字符串的列表
        n:位数
        返回十六进制字符串
    }
    '''
    String = ''
    for j in range(n):
        String += hex(
            i[4 * j] * 8 + i[4 * j + 1] * 4 + i[4 * j + 2] * 2 + i[4 * j + 3] * 1)[
                  2:].upper()
    return String

#F函数
def F_function(R,K):
    '''
        args = {
            R:右半部分,二进制串列表,32位
            K:经过置换选择2的密钥二进制串列表,48位
            返回值:
            R:经过F函数加工后的二进制串列表,右半部分,32位
        }
    '''
    extend = []
    for i in range(48):#扩展置换(E表)
        extend.append(R[E_table[i]-1])
    R.clear()
    for i in range(48):#扩展后的列表与密钥列表异或
        R.append(extend[i]^K[i])
    extend.clear()
    for i in range(8):#S盒变换
        row = R[i*6]*2 + R[i*6+5]
        col = R[i*6+1]*8 + R[i*6+2]*4 + R[i*6+3]*2 + R[i*6+4]
        num = S_box[i][16*row+col]
        str = "{0:b}".format(num).zfill(4)
        extend.extend(int(m) for m in str)
    R.clear()
    for i in range(32):#P表置换
        R.append(extend[P_table[i]-1])
    return R

#将秘钥压缩成56位
def miyao1(keystring,mode=1):
    '''
        args = {
            keystring:密钥字符串
            mode:转换模式,如果为1,则使用十六进制;如果为2,则使用unicode编码,16位,可加密中文;如果为3,使用unicode编码,8位
            返回值:
            K1:返回压缩后的密钥列表,56位
        }
    '''
    K = StringToBit(keystring,mode)[0]
    K1 = []
    for i in range(56):
        K1.append( K[PC1_table[i]-1])
    return K1

#求密钥集合
def miyao(K,RoundNum=16):
    '''
        args = {
            K:压缩后的密钥二进制字符列表,56位
            RoundNum:轮数
            返回值:
            keylist:返回移位和置换选择2后的列表,包括没一轮的结果,形如[['0','1','0'.....]['0','0','0'....]],其中每个列表中有56位
        }
    '''
    keylist = []
    for j in range(RoundNum):
        C = K[0:28]
        D = K[28:56]
        for i in range(left_rotations[j]):#移位
            C.insert(len(C),C[0])
            C.remove(C[0])
            D.insert(len(D), D[0])
            D.remove(D[0])
        K.clear()
        K = C+D
        K1 = []
        for i in range(48):#密钥置换选择2
            K1.append(K[PC2_table[i]-1])
        keylist.append(K1)
    return keylist

#加解密函数
def DESEncrpty(text,keystring,Roundnum=16,way=1,mode=1):
    '''
        args = {
            text:需要加密或者解密的字符串
            keystring:密钥字符串
            RoundNum:轮数
            way:加密或者解密,1表示加密,2表示解密
            mode:转换模式,如果为1,则使用十六进制;如果为2,则使用unicode编码,16位,可加密中文;如果为3,使用unicode编码,8位
            返回值:
            str1:返回加密或者解密后的字符串
        }
    '''
    Bit = []
    textBit = StringToBit(text,mode)
    keybit = miyao1(keystring,mode)
    if way==1:#加密时,密钥列表正用
        keybitlist = miyao(keybit,Roundnum)
    else:#解密时,密钥列表逆置
        keybitlist = miyao(keybit, Roundnum)
        keybitlist.reverse()
    for i in textBit:#取64位bit串
        text1 = []
        for j in range(64):#初始置换
            text1.append(i[IP_table[j] - 1])
        L = text1[0:32]#左半部分
        R = text1[32:64]#右半部分
        print("初始置换后:   左:" + bitTTToString(L, 8) + "   右:" + bitTTToString(R, 8))
        for j in range(Roundnum):#开始每轮的加密
            temp = R.copy()
            # print(R)
            # print(keybitlist[j])
            R = F_function(R,keybitlist[j])
            for m in range(32):#左右两边异或得到下一轮右边
                R[m] = L[m]^R[m]
            L = temp#下一轮右边即为上一轮左边
            print("第"+str((j+1))+"轮  "+"左:" + bitTTToString(L, 8) + "   右:" + bitTTToString(R, 8)+"   密钥:"+bitTTToString(keybitlist[j],12))
        L,R = R,L#最后左右两边置换
        print("左右两边交换后:   左:" + bitTTToString(L, 8) + "   右:" + bitTTToString(R, 8))
        Bit1 = L+R
        print("左右部分合在一起:"+bitTTToString(L+R,16))
        Bit2 = []
        for j in range(64):#逆初始置换
            Bit2.append(Bit1[IP_Inverse_table[j] - 1])
        print("逆初始置换后:" + bitTTToString(Bit2, 16))
        Bit.append(Bit2)

    #转换成密文字符串
    str1 = BitToString(Bit,mode)
    return str1

if __name__ == "__main__":
    choice = 1
    while choice:
        choice = int(input("请输入选择[1]加密[2]解密[0]退出:"))
        mode = int(input("请输入模式[1]十六进制[2]16位[3]8位:"))
        Roundnum = int(input("请输入轮数:"))
        if choice==1:
            text = input("请输入需要加密的明文:")
            key = input("请输入密钥(模式1输入16位,模式2输入4位,模式3输入8位):")
            str1 = DESEncrpty(text,key,Roundnum,choice,mode)
            print("加密后的字符串:"+str1)
        elif choice==2:
            text = input("请输入需要解密的密文:")
            key = input("请输入密钥(模式1输入16位,模式2输入4位,模式3输入8位):")
            str1 = DESEncrpty(text, key, Roundnum,choice,mode)
            print("解密后的字符串:" + str1)
        else:
            break


#明文:123456ABCD132536
#密钥:AABB09182736CCDD
#密文:C0B7A8D05F3A829C```


  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值