密码学课程设计-DES的加密与解密

DES算法流程:

1. 64位明文经过初始置换(IP)重新排列,并且将其分为左右两个分组:L0,R0。各32位

2. 密钥扩展。

3. 在密钥的参与下,最左右两个分组进行16轮相同函数的迭代,每轮迭代都有置换和代换。注意最后一轮迭代的输出为64位。左半部分和右半部分不进行交换。

4. 最后的与输出再通过逆初始置换(IP-1)产生64位密文。

初始置换(IP)

64位明文经过初始置换(IP)重新排列,并且将其分为左右两个分组:L0,R0。各32位

def Exchagne_IP(M):
    x = [0] * len(M)
    for i in range(len(IP_table)):
        x[i] = M[IP_table[i] - 1]
    # print(x)
    L = [0] * (len(M) // 2)
    R = [0] * (len(M) // 2)
    for i in range(len(L)):
        L[i] = x[i]
    for i in range(len(R)):
        R[i] = x[i + len(L)]
    return L, R

 

密钥扩展

1.64位密钥通过置换选择PC-1得到56位有效密钥。

分成两个28位数据C0, D0。

每轮迭代中,Ci-1和Di-1分别循环左移一定位数,结果作为下一轮输入。同时,结果通过PC-2产生48位输出,作为子密钥。 


# 生成子密钥总函数
def Create_FINAL_KEY(C0, D0):
    CI = C0
    DI = D0
    for i in range(16):  # 0~15
        CI, DI = rol(CI, DI, i)  # 循环左移 对
        Change_With_PC2(CI, DI)  #


def
Enlarge_Key(K): K1 = [] D0 = [] C0 = [] t = 0 # 置换选择1 for i in range(len(PC_1)): K1.append(K[PC_1[i] - 1]) # 形成C0,D0 for i in range(28): C0.append(K1[i]) for i in range(28): D0.append(K1[i + 28]) Create_FINAL_KEY(C0, D0)

 

轮函数F

有四个组成:扩展置换(E盒),密钥加非线性代换(S盒),线性置换(P盒)

# f函数
def f(R, num):  # num从0~15
    x1 = E_Exchange(R)  # 扩展置换
    x2 = func_xor(x1, K_final[num])  # 异或
    # print("Xor", binarray_to_str(x2))
    x3 = S_Exchange(x2)  # 48位一维数组进入S盒
    # print()
    # print("S: ", binarray_to_str(x3))
    x4 = P_Exchange(x3)  # 32位一维数组进入P盒
    return x4

 

扩展置换

32位输入扩展为48位输出。将48位输出按8行6列的E盒进行置换。快速实现雪崩效应。

# 扩展置换
def E_Exchange(R):
    x = [0] * len(E)
    for i in range(len(E)):
        x[i] = R[E[i] - 1]
    return x

密钥轮加

E盒出的48位于48位子密钥逐个异或。

def func_xor(x1, x2):
    if len(x1) != len(x2):
        print("xor:输入字符串长度不等")
    else:
        res = [0] * len(x1)
        for i in range(len(x1)):
            res[i] = chr_xor(x1[i], x2[i])  # 逐个字符异或
        return res

代换盒(S)

密钥轮加48位压缩成32位。8个S盒,均6进4出。查询方法:b1~b6, b1b6两位 ->行, b2b3b4b5四位->列。

# S盒置换
def S_Exchange(input):  # 输入是
    res = []
    s_num = 0  # S盒的编号
    # print("S盒16进制:",end = '')
    for i in range(0, len(input), 6):
        temp = input[i:i + 6]  # 先把当前切片拿出来
        x = int(temp[0] + temp[5], 2)  #
        y = int(temp[1] + temp[2] + temp[3] + temp[4], 2)  #
        out = bin(S[s_num][16 * x + y])[2:].rjust(4, "0")  # 查表,输出四位二进制字符串
        # print(S[s_num][16 * x + y],end=' ')
        s_num += 1
        for j in range(4):  # 四位二进制数字符串放进结果,共32位
            res.append(out[j])
    return res

置换运算(P)

32位数据经过P盒置换。输出。

# P盒置换
def P_Exchange(input):  # 32位输入
    res = [0] * len(P)
    for i in range(len(P)):
        res[i] = input[P[i] - 1]
    return res

IP-1逆置换

def Exchange_IP_1(input):
    if len(input) != 64:
        print("len_input is not 64!")
        return 0
    else:
        res = []
        for i in range(len(IP_1)):
            res.append(input[IP_1[i] - 1])
        return res

DES加密部分

def DES_encrypt(M, K):  # 明文字符串,密文字符串,加密结果
    # M0 = str_to_bin(M)  #√
    # K0 = str_to_bin(K)  #√
    # M = hex_to_bin(M)
    # K = hex_to_bin(K)
    L, R = Exchagne_IP(M)  # 初始置换,得到L0,R0 #√
    # print(bin_to_hex(L+R))
    Enlarge_Key(K)  # 扩展密钥,直接生成子密钥集合
    # for i in range(16):
    #     print(bin_to_hex(K_final[i]))
    # print(K_final)
    # 0~14 轮,共前15轮, 最后一轮外面写
    for i in range(15):
        temp = R  # 给temp,到时候赋给new_L
        after_f = f(R, i)  # 进入F函数
        R = func_xor(L, after_f)  # 出来异或
        L = temp  # R给L
        # print("ROUND",i,end=' : ')
        # print(bin_to_hex(L),end=' ')
        # print(bin_to_hex(R))
    # 第16轮
    R_final = R
    after_f = f(R, 15)
    L_final = func_xor(L, after_f)
    # IP逆盒
    res_bin = Exchange_IP_1(L_final + R_final)
    res_fianl = bin_to_hex(res_bin)  # 16进制输出
    # res_fianl = binarray_to_str(res_bin)
    return res_fianl

DES解密部分

def DES_decrypt(enc, K):
    # print(enc)
    # enc1 = hex_to_bin(enc)  # 变成0-1数组
    # K = hex_to_bin(K)
    # print(enc1)
    Enlarge_Key(K)
    new_L, new_R = Exchagne_IP(enc)
    for i in range(15, 0, -1):  # 15~1
        temp = new_R
        new_R = func_xor(new_L, f(new_R, i))
        new_L = temp
    final_L = func_xor(new_L, f(new_R, 0))
    final_R = new_R
    final = final_L + final_R
    res = Exchange_IP_1(final)
    res = bin_to_hex(res)
    return res

测试正确性

由于代码都是自己手写的,加上本人水平很一般,代码会有很多冗余和错误。在debug的时候我找了很多文本,均没有达到debug的效果。最后我找到了这个网址:

https://www.geeksforgeeks.org/data-encryption-standard-des-set-1/

加密和解密结果都能够对应上。(大小写区别请忽略)

 

 

 

 这个DES真的写的头疼,主要原因是自己是真菜,应该多借鉴一下大佬作品,而不是闭门造车。

完整代码

同时也会上传到github上,有兴趣来玩呀。

# 初始密钥:64位(8字节)  有效密钥:56位(7字节)  明文:64位的倍数(8字节)
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]
# 子密钥集合
K_final = []
IP_1 = [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, ]
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_1_C = [[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, ]]
PC_1_D = [[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, ]
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],

]  # S盒
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, ]
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]


# 字符串变成二进制流一维数组
def str_to_bin(a):
    S = a.encode("utf-8").hex()  # 转换成16进制ASCII,两位一个字符
    z = [0] * 4 * len(S)  # 最终存放数组
    for i in range(len(S)):
        x = bin(int(S[i]))[2:].rjust(4, "0")  # 转换成4位二进制形式字符串
        for j in range(4):
            z[i * 4 + j] = x[j]
    return z


# 初始置换IP
def Exchagne_IP(M):
    x = [0] * len(M)
    for i in range(len(IP_table)):
        x[i] = M[IP_table[i] - 1]
    # print(x)
    L = [0] * (len(M) // 2)
    R = [0] * (len(M) // 2)
    for i in range(len(L)):
        L[i] = x[i]
    for i in range(len(R)):
        R[i] = x[i + len(L)]
    return L, R


# 循环左移
def rol(C0, D0, num):  # C0,D0是32位长度一位数组
    rol_num = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]  # 循环次数数组,从0开始
    C1 = C0
    D1 = D0
    for i in range(rol_num[num]):
        x = C1[0]
        y = D1[0]
        for j in range(len(C0) - 1):
            C1[j] = C1[j + 1]
            D1[j] = D1[j + 1]
        C1[len(C1) - 1] = x
        D1[len(D1) - 1] = y
    return C0, D0


# PC-2扩展,并且直接放到子密钥表中
def Change_With_PC2(CI, DI):
    K = [0] * (len(CI) * 2)
    # 先合并放到K中,一位数组
    for i in range(len(K)):
        if i < len(CI):
            K[i] = CI[i]
        else:
            K[i] = DI[i - len(CI)]
    K1 = [0] * 48
    # PC-2置换
    for i in range(48):
        K1[i] = K[PC_2[i] - 1]
    # 放到总的K子密钥数组中
    K_final.append(K1)


# 生成子密钥总函数
def Create_FINAL_KEY(C0, D0):
    CI = C0
    DI = D0
    for i in range(16):  # 0~15
        CI, DI = rol(CI, DI, i)  # 循环左移 对
        Change_With_PC2(CI, DI)  #


# 密钥扩展
def Enlarge_Key(K):
    K1 = []
    D0 = []
    C0 = []
    t = 0
    # 置换选择1
    for i in range(len(PC_1)):
        K1.append(K[PC_1[i] - 1])
    # 形成C0,D0
    for i in range(28):
        C0.append(K1[i])
    for i in range(28):
        D0.append(K1[i + 28])
    Create_FINAL_KEY(C0, D0)


# 扩展置换
def E_Exchange(R):
    x = [0] * len(E)
    for i in range(len(E)):
        x[i] = R[E[i] - 1]
    return x


# 实现字符异或
def chr_xor(a, b):
    if (a == '1' and b == '1') or (a == '0' and b == '0'):
        return '0'
    elif (a == '1' and b == '0') or (a == '0' and b == '1'):
        return '1'
    else:
        print("chr_xor num is not 0,1")
        return '0'


# 两个长度相等的字符串的异或(两个一维数组的异或)
def func_xor(x1, x2):
    if len(x1) != len(x2):
        print("xor:输入字符串长度不等")
    else:
        res = [0] * len(x1)
        for i in range(len(x1)):
            res[i] = chr_xor(x1[i], x2[i])  # 逐个字符异或
        return res


# S盒置换
def S_Exchange(input):  # 输入是
    res = []
    s_num = 0  # S盒的编号
    # print("S盒16进制:",end = '')
    for i in range(0, len(input), 6):
        temp = input[i:i + 6]  # 先把当前切片拿出来
        x = int(temp[0] + temp[5], 2)  #
        y = int(temp[1] + temp[2] + temp[3] + temp[4], 2)  #
        out = bin(S[s_num][16 * x + y])[2:].rjust(4, "0")  # 查表,输出四位二进制字符串
        # print(S[s_num][16 * x + y],end=' ')
        s_num += 1
        for j in range(4):  # 四位二进制数字符串放进结果,共32位
            res.append(out[j])
    return res


# P盒置换
def P_Exchange(input):  # 32位输入
    res = [0] * len(P)
    for i in range(len(P)):
        res[i] = input[P[i] - 1]
    return res


# f函数
def f(R, num):  # num从0~15
    x1 = E_Exchange(R)  # 扩展置换
    x2 = func_xor(x1, K_final[num])  # 异或
    # print("Xor", binarray_to_str(x2))
    x3 = S_Exchange(x2)  # 48位一维数组进入S盒
    # print()
    # print("S: ", binarray_to_str(x3))
    x4 = P_Exchange(x3)  # 32位一维数组进入P盒
    return x4


# IP-1逆置换
def Exchange_IP_1(input):
    if len(input) != 64:
        print("len_input is not 64!")
        return 0
    else:
        res = []
        for i in range(len(IP_1)):
            res.append(input[IP_1[i] - 1])
        return res


# 二进制一位数组转换成0.1字符串
def binarray_to_str(input):
    res = ''
    for i in range(len(input)):
        res += input[i]
    return res


# 二进制转换成16进制输出
def bin_to_hex(input):
    a = binarray_to_str(input)
    res = ''
    for i in range(0, len(input), 4):
        temp = a[i:i + 4]  # 取当前
        res += hex(int(temp, 2))[2:]
    return res


# 16进制字符串转成二进制一位数组
def hex_to_bin(input):
    res = []
    for i in range(len(input)):  # 取一位数据,生成4位二进制
        a = bin(int(input[i], 16))[2:].rjust(4, "0")
        for j in range(4):
            res.append(a[j])
    return res


# AES加密
def DES_encrypt(M, K):  # 明文字符串,密文字符串,加密结果
    # M0 = str_to_bin(M)  #√
    # K0 = str_to_bin(K)  #√
    # M = hex_to_bin(M)
    # K = hex_to_bin(K)
    L, R = Exchagne_IP(M)  # 初始置换,得到L0,R0 #√
    # print(bin_to_hex(L+R))
    Enlarge_Key(K)  # 扩展密钥,直接生成子密钥集合
    # for i in range(16):
    #     print(bin_to_hex(K_final[i]))
    # print(K_final)
    # 0~14 轮,共前15轮, 最后一轮外面写
    for i in range(15):
        temp = R  # 给temp,到时候赋给new_L
        after_f = f(R, i)  # 进入F函数
        R = func_xor(L, after_f)  # 出来异或
        L = temp  # R给L
        # print("ROUND",i,end=' : ')
        # print(bin_to_hex(L),end=' ')
        # print(bin_to_hex(R))
    # 第16轮
    R_final = R
    after_f = f(R, 15)
    L_final = func_xor(L, after_f)
    # IP逆盒
    res_bin = Exchange_IP_1(L_final + R_final)
    res_fianl = bin_to_hex(res_bin)  # 16进制输出
    # res_fianl = binarray_to_str(res_bin)
    return res_fianl


def DES_decrypt(enc, K):
    # print(enc)
    # enc1 = hex_to_bin(enc)  # 变成0-1数组
    # K = hex_to_bin(K)
    # print(enc1)
    Enlarge_Key(K)
    new_L, new_R = Exchagne_IP(enc)
    for i in range(15, 0, -1):  # 15~1
        temp = new_R
        new_R = func_xor(new_L, f(new_R, i))
        new_L = temp
    final_L = func_xor(new_L, f(new_R, 0))
    final_R = new_R
    final = final_L + final_R
    res = Exchange_IP_1(final)
    res = bin_to_hex(res)
    return res


# 检查明文长度,如果小于64,用0补齐,如果大于,切片,返回一个整的一维数组
def check_len_M(M):
    res = []
    if len(M) <= 64:
        res += M
        for i in range(64 - len(M)):
            res.append("0")
        return res
    else:
        t = len(M) % 64
        for i in range(64 - t):
            M.append("0")
        for i in range(len(M) // 64):
            res += M[i * 64:i * 64 + 64]
        return res


# 密钥不够64位就补齐64位,返回一位数组
def check_len_K(K):
    res = K
    if len(K) > 64:
        print("error!")
        return 0
    for i in range(64 - len(K)):
        res += '0'
    return res


# 查看密文是否是64位倍数
def check_len_enc(enc):
    if len(enc) % 64 != 0:
        print("enc input wrong!")
        return 0


# 开始加密
def enc_begin(M, K):
    M = hex_to_bin(M)
    K = hex_to_bin(K)
    M0 = check_len_M(M)
    K0 = check_len_K(K)
    res = ''
    for i in range(len(M0) // 64):  # 一维大数组切片,然后加密完拼接
        res += DES_encrypt(M0[i * 64:i * 64 + 64], K0)
    return res


# 开始解密
def decry_begin(enc, K):
    enc1 = hex_to_bin(enc)
    K1 = hex_to_bin(K)
    check_len_enc(enc1)
    K2 = check_len_K(K1)
    res = ''
    for i in range(len(enc1) // 64):
        res += DES_decrypt(enc1[i * 64:i * 64 + 64], K2)
    return res


# main
# M = '123456ABCD132536'  # 8字节明文
# K = 'AABB09182736CCDD'  # 64位密钥
print("plz input your choise")
print("1: encrypt by DES")
print("2:decrypt by DES")
flag = input("")
if flag == "1":
    M = input("plz input your text (hex with 64 bit): ")
    K = input("plz input your key (hex with 64 bit): ")
    enc = enc_begin(M, K)
    print("The Cipher Text(hex) is : ", enc)
elif flag == "2":
    enc = input("plz input your Cipher Text (hex Integer multiples of 64): ")
    K = input("plz input your key (hex with 64 bit): ")
    res = decry_begin(enc, K)
    print("The Plain Text(hex) is : ", res)
else:
    print("wrong!")

 

posted @ 2020-12-28 16:34  Evening_Breeze  阅读(494)  评论(0编辑  收藏  举报