Created
July 7, 2020 10:08
-
-
Save Dreace/4fc39e0ec2615ad06554e4ef9b9c64b6 to your computer and use it in GitHub Desktop.
使用 Python 实现 DES 算法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import chain | |
from typing import List, Tuple | |
from .tables import * | |
class DES: | |
def __init__(self, key: [str, bytes]): | |
if isinstance(key, str): | |
key = key.encode() | |
if len(key) > 8: | |
key = key[8:] | |
elif len(key) < 8: | |
key += b"".join(b"\x00" for _ in range(8 - len(key))) | |
key_bit_list = self._bytes_to_bit_list(key) | |
left_half_key_block = self._transform(key_bit_list, pc1_left_table) | |
right_half_key_block = self._transform(key_bit_list, pc1_right_table) | |
sub_key_list = [] | |
for round_index in range(16): | |
left_half_key_block = self._circle_left_shift(left_half_key_block, key_left_shift_bits[round_index]) | |
right_half_key_block = self._circle_left_shift(right_half_key_block, key_left_shift_bits[round_index]) | |
sub_key_list.append(self._transform(left_half_key_block + right_half_key_block, pc2_table)) | |
self._sub_key_list = sub_key_list | |
def encrypt(self, plain_text: [str, bytes]): | |
if isinstance(plain_text, str): | |
plain_text = plain_text.encode() | |
plain_text_len = len(plain_text) | |
if plain_text_len % 8: | |
plain_text += b"".join(b"\x00" for _ in range(8 - plain_text_len % 8)) | |
encrypted_blocks = [] | |
for block in map(lambda s: plain_text[s:s + 8], range(0, plain_text_len, 8)): | |
encrypted_blocks.append(self._encrypt_block(self._bytes_to_bit_list(block))) | |
encrypted_bit_list = list(chain(*encrypted_blocks)) | |
return self._bit_list_to_bytes(encrypted_bit_list) | |
def decrypt(self, cipher_text: bytes) -> str: | |
self._sub_key_list.reverse() | |
plain_text = self.encrypt(cipher_text) | |
self._sub_key_list.reverse() | |
return plain_text.decode().rstrip('\0') | |
def _encrypt_block(self, plain_block: List[int]) -> List[int]: | |
plain_block = self._transform(plain_block, ip_table) | |
left_half_block = plain_block[:32] | |
right_half_block = plain_block[32:] | |
for round_index in range(16): | |
left_half_block, right_half_block = right_half_block, \ | |
self._bit_list_xor( | |
left_half_block, | |
self._transform( | |
self._s_box_transform( | |
self._bit_list_xor( | |
self._transform(right_half_block, | |
extend_table), | |
self._sub_key_list[round_index] | |
) | |
), p_table | |
) | |
) | |
return self._transform(right_half_block + left_half_block, fp_table) | |
@staticmethod | |
def _transform(raw_list: list, transform_table: List[int]) -> list: | |
return list(map(lambda index: raw_list[index], transform_table)) | |
@staticmethod | |
def _bytes_to_bit_list(input_bytes: bytes) -> List[int]: | |
bit_list = [0] * 8 * len(input_bytes) | |
index = 0 | |
for char_ascii in input_bytes: | |
loc = 7 | |
while loc >= 0: | |
bit_list[index] = 0 if char_ascii & (1 << loc) == 0 else 1 | |
loc -= 1 | |
index += 1 | |
return bit_list | |
@staticmethod | |
def _bit_list_to_bytes(bit_list: List[int]) -> bytes: | |
char_ascii = 0 | |
byte_list = [] | |
for index, bit in enumerate(bit_list): | |
char_ascii += bit << (7 - index % 8) | |
if index % 8 == 7: | |
byte_list.append(char_ascii) | |
char_ascii = 0 | |
return bytes(byte_list) | |
@staticmethod | |
def _circle_left_shift(input_list: list, bits: int) -> list: | |
return input_list[bits:] + input_list[:bits] | |
@staticmethod | |
def _bit_list_xor(left: list, right: list) -> List[str]: | |
return list(map(lambda x, y: x ^ y, left, right)) | |
@staticmethod | |
def _s_box_transform(input_list: list) -> list: | |
transformed = [0 for _ in range(32)] | |
transformed_index = 0 | |
r = 0 | |
while r < 48: | |
m = (input_list[r] << 1) + input_list[r + 5] | |
n = (input_list[r + 1] << 3) + (input_list[r + 2] << 2) + (input_list[r + 3] << 1) + (input_list[r + 4]) | |
s_value = s_box_tables[r // 6][(m << 4) + n] | |
transformed[transformed_index] = (s_value & 8) >> 3 | |
transformed[transformed_index + 1] = (s_value & 4) >> 2 | |
transformed[transformed_index + 2] = (s_value & 2) >> 1 | |
transformed[transformed_index + 3] = s_value & 1 | |
r += 6 | |
transformed_index += 4 | |
return transformed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ip_table = [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] | |
fp_table = [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] | |
extend_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] | |
pc1_left_table = [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] | |
pc1_right_table = [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_table = [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] | |
key_left_shift_bits = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1] | |
p_table = [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] | |
s_box_tables = [[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]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment