一、加密
1、秘钥处理
DES算法会先对64位密钥进行处理生成48位子密钥后再参与到算法的轮操作中,在每一轮的迭代过程中,使用不同的子密钥。其中的处理包括置换选择、循环左移、压缩置换。
1.1 置换选择
DES秘钥有64位,其中每8位有一个校验位,所以有56位的子密钥。根据下表生成56位密钥,并将置换后的56位密钥分成两部分C0和D0,每部分28位:
注意:这里的数字表示的是原数据的位置,不是数据,例:把第57位放在第1位
# 置换函数,用于密钥置换、IP置换、P置换等
def __substitution(self, table: str, self_table: list) -> str:
"""
:param table: 需要进行置换的列表,是一个01字符串
:param self_table: 置换表,在__init__中初始化了
:return: 返回置换后的01字符串
"""
sub_result = ""
for i in self_table:
sub_result += table[i - 1]
return sub_result
# 返回加密过程中16轮的子密钥
def __get_key_list(self):
"""
:return: 返回加密过程中16轮的子密钥
"""
key = self.__substitution(self.K, self.k1) # 置换
left_key = key[0:28]
right_key = key[28:56]
keys = []
for i in range(1, 17): # 循环左移
move = self.k0[i - 1]
move_left = left_key[move:28] + left_key[0:move]
move_right = right_key[move:28] + right_key[0:move]
left_key = move_left
right_key = move_right
move_key = left_key + right_key
ki = self.__substitution(move_key, self.k2) # 压缩置换
keys.append(ki)
return keys
def key_conversion(self, key):
"""
将64位原始密钥转换为56位的密钥,并进行一次置换
"""
first_key = key
key_replace_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
)
return self.replace_block(first_key, key_replace_table)
1.2 循环左移
将C0和D0进行循环左移变化(注:每轮循环左移的位数由轮数决定(如下图)),变换后生成C1和D1,然后C1和D1合并。
def spin_key(self, key: str):
"""
旋转获得子密钥
"""
kc = self.key_conversion(key)
first, second = kc[0: 28], kc[28: 56]
spin_table = (1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28)
for i in range(1, 17):
first_after_spin = first[spin_table[i - 1]:] + first[:spin_table[i - 1]]
second_after_spin = second[spin_table[i - 1]:] + second[:spin_table[i - 1]]
print(f"旋转后的key: left: {first_after_spin}, right: {second_after_spin}")
yield first_after_spin + second_after_spin
1.3 压缩置换
移动后,从56位中选出48位。这个过程中,既置换了每位的顺序,又选择了子密钥,因此称为压缩置换。压缩置换规则如PC-2表(注意表中没有9,18,22,25,35,38,43和54这8位)
压缩置换后的48位子密钥将参与到轮操作中,而C1、D1也将再进行左移和置换后得到下一轮的子密钥。
def key_selection_replacement(self, key: str):
"""
通过选择置换得到48位的子密钥
"""
key_select_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
)
for child_key56 in self.spin_key(key):
self.child_keys.append(self.replace_block(child_key56, key_select_table))
# 置换函数,用于密钥置换、IP置换、P置换等
def __substitution(self, table: str, self_table: list) -> str:
"""
:param table: 需要进行置换的列表,是一个01字符串
:param self_table: 置换表,在__init__中初始化了
:return: 返回置换后的01字符串
"""
sub_result = ""
for i in self_table:
sub_result += table[i - 1]
return sub_result
# 返回加密过程中16轮的子密钥
def __get_key_list(self):
"""
:return: 返回加密过程中16轮的子密钥
"""
key = self.__substitution(self.K, self.k1) # 置换
left_key = key[0:28]
right_key = key[28:56]
keys = []
for i in range(1, 17): # 循环左移
move = self.k0[i - 1]
move_left = left_key[move:28] + left_key[0:move]
move_right = right_key[move:28] + right_key[0:move]
left_key = move_left
right_key = move_right
move_key = left_key + right_key
ki = self.__substitution(move_key, self.k2) # 压缩置换
keys.append(ki)
return keys
2.明文处理
2.1 将明文变为二进制
将字符串的明文转换为二进制,按64位一组,分成若干组,如果不够64位,就补零。
from bitarray import bitarray
@staticmethod
def _bit_encode(s: str) -> str:
"""
将字符串转换为01字符串的形式
"""
return bitarray(
''.join([bin(int('1' + hex(c)[2:], 16))[3:]
for c in s.encode('utf-8')])).to01()
def processing_encode_input(self, enter: str) -> list:
"""
将输入的字符串转换为二进制形式,并没64位为一组进行分割
"""
result = []
bit_string = self._bit_encode(enter)
# 如果长度不能被64整除,就补零
if len(bit_string) %