DES python代码的具体实现

_IP = [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,
56, 48, 40, 32, 24, 16, 8, 0,
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
return list(map(lambda x: plain[x], _IP))

 DES先将64位的明文经过初始轮置换(IP)置换,这是一个固定的置换列表,函数 IP 接受一个整数列表 plain 作为输入,然后使用 _IP 列表中的值作为索引,对输入列表进行置换操作。

 代码使用了List类型,应该导入模板 from typing import List

__pc1 = [56, 48, 40, 32, 24, 16, 8,
0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26,
18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14,
6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28,
20, 12, 4, 27, 19, 11, 3
]

__pc2 = [
13, 16, 10, 23, 0, 4,
2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7,
15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54,
29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52,
45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

定义了两个置换表 __pc1 和 __pc2,以及一个旋转列表 ROTATIONS,具体来说,它将密钥中的某些位按照 __pc1 中的顺序重新排列。__pc1 中的每个元素表示密钥中的一个位的位置,例如,__pc1[0] 表示密钥中的第 57 位,__pc1[1] 表示密钥中的第 49 位,以此类推。

置换表 __pc2 也是用于密钥生成过程的表,它将经过置换表 __pc1 处理后的密钥再次进行置换。它的作用是从 56 位的密钥中选择出 48 位的子密钥。__pc2 中的每个元素表示经过 __pc1 处理后的密钥中的一个位的位置。

旋转列表 ROTATIONS 是用于密钥生成过程中的密钥旋转操作的规则。DES 算法中,密钥需要进行循环左移操作,根据 ROTATIONS 中的规则确定每一轮循环左移的位数。ROTATIONS 中的每个元素表示第几轮循环左移需要左移的位数。

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(key: List[int]):
    key = PC_1(key) # PC-1置换
    L, R = key[:28], key[28:] # 分成两半

    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

函数 PC_1 接受一个长度为 64 的二进制密钥列表 key,并使用置换表 __pc1 对其进行置换操作

函数 PC_2 接受一个经过 PC_1 处理后的长度为 56 的二进制密钥列表 key,并使用置换表 __pc2 对其进行置换操作。它从 56 位的密钥中选择出 48 位的子密钥,并返回子密钥的列表。

函数 get_sub_key 接受一个长度为 64 的二进制密钥列表 key,并通过调用 PC_1 函数对密钥进行置换。然后,它将置换后的密钥列表分成两半,分别表示为 L 和 R。接下来,根据预定义的循环左移规则 ROTATIONS,对 L 和 R 进行相应的循环左移操作。循环左移的位数由 ROTATIONS 中的值确定。然后,将左移后的 L 和 R 合并,并调用 PC_2 函数对合并后的列表进行置换,得到子密钥。最后,将所有子密钥存储在列表 skeys 中,并返回该列表。

__expansion_table = [
	31,  0,  1,  2,  3,  4,
	 3,  4,  5,  6,  7,  8,
	 7,  8,  9, 10, 11, 12,
	11, 12, 13, 14, 15, 16,
	15, 16, 17, 18, 19, 20,
	19, 20, 21, 22, 23, 24,
	23, 24, 25, 26, 27, 28,
	27, 28, 29, 30, 31,  0
]

定义了扩展置换表 __expansion_table,是一个长度为 48 的表,用于将 32 位的数据块扩展为 48 位

__sbox = [
		# 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],
	]

定义了 DES 算法中的 S 盒(Substitution Box)__sbox,它将输入的 6 位数据块映射为 4 位输出,在 DES 算法中,一共有 8 个 S 盒,每个 S 盒都是一个 4x16 的表格,其中每个元素表示一个 4 位的输出。

__sbox 是一个包含 8 个 S 盒的列表。每个 S 盒都用一个二维列表表示,其中每行代表一个输入的可能取值(0-15),每列代表对应的输出

S 盒在 DES 算法的轮函数中起到了非线性变换的作用,在 DES 的加密和解密过程中,会根据输入的数据块的不同,选择对应的 S 盒进行替换操作,从而完成一轮的加密或解密运算。

__p = [
	15, 6, 19, 20, 28, 11,
	27, 16, 0, 14, 22, 25,
	4, 17, 30, 9, 1, 7,
	23,13, 31, 26, 2, 8,
	18, 12, 29, 5, 21, 10,
	3, 24
]

这是P置换表,在加密过程中,经过一系列的轮函数操作后,数据块会经过 P 置换操作,将其重新排列。在解密过程中,也会进行逆向的 P 置换操作,将加密后的数据块恢复为原始的数据块。

 

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    """
    index: 代表这是第几轮
    R: 输入数据
    skeys: 子密钥数组
    """
    R = EP(R)  # 扩展置换
    R = list(map(lambda x, y: x ^ y, R, skeys[index]))  # 异或

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

这是DES算法中的关键步骤——轮函数操作f

  1. EP(data: List[int]) 函数是扩展置换(Expansion Permutation)操作,它接受一个长度为 32 的数据块 data,并根据 DES 算法的扩展置换表 __expansion_table 对数据块进行扩展置换。扩展置换将 32 位数据扩展为 48 位数据,返回扩展后的结果。

  2. P(data: List[int]) 函数是 P 置换(Permutation)操作,它接受一个长度为 32 的数据块 data,并根据 DES 算法的 P 置换表 __p 对数据块进行置换。P 置换将数据块中的位重新排列,返回重新排列后的结果。

  3. F(index: int, R: List[int], skeys: List[List[int]]) 函数是 DES 算法中的轮函数操作,用于对右半部分数据进行处理。它接受一个表示第几轮的索引 index,右半部分数据 R,以及子密钥数组 skeys。          

在函数内部,首先对右半部分数据进行扩展置换,即调用 EP(R)。扩展置换将 32 位数据扩展为 48 位数据。

然后,将扩展置换后的数据与对应轮次的子密钥进行异或操作。子密钥是从 skeys 数组中根据索引 index 获取的。

接下来,将异或后的结果分成 8 个 6 位的块,存储在列表 B 中。

然后,对每个块应用 S 盒替换。通过计算每个块的行坐标和列坐标,从预定义的 S 盒 __sbox 中获取相应的值,并将其转换为二进制形式存储在列表 Bn 中。

最后,将经过 S 盒替换后的结果进行 P 置换,即调用 P(Bn),并返回最终的结果。

     

_FP = [
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,
32, 0, 40, 8, 48, 16, 56, 24
]

def FP(plain: List[int]):
return list(map(lambda x: plain[x], _FP))

 _FP 是 DES 算法中的最终置换表,是一个长度为 64 的列表,列表中的每个元素表示输出数据块中对应位置的输入位置,_FP[0] 表示输出数据块中的第一个位置对应输入数据块中的第 39 个位置,_FP[1] 表示输出数据块中的第二个位置对应输入数据块中的第 7 个位置


key = b'12345678'
plain = b'12345678'

# 转为二进制数组
key = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in key])
plain = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in plain])
skeys = get_sub_key(key)//获取子密钥数组

block = IP(plain)//对明文进行初始置换

L, R = block[:32], block[32:]//将明文分为左右两部分
for i in range(16)://16轮的加密操作
    tpR = R[:]
    R = F(i, R, skeys)
    R = list(map(lambda x, y: x ^ y, R, L))
    L = tpR
block = R + L
block = FP(block)//终极置换
enc = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])//转化为字节的形式
    
print(enc)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值