DES的原理及python實現

DES加密算法原理及實現

DES是一種對稱加密算法【即發送者與接收者持有相同的密鑰】,它的基本原理是將要加密的數據劃分為n個64位的塊,然后使用一個56位的密鑰逐個加密每一個64位的塊,得到n個64位的密文塊,最后將密文塊拼接起來得到最終的密文

加密

加密過程

DES加密過程接收一個明文盒一個64位的密鑰key,明文字符串會被轉換為對各64位的塊,加密過程以塊位單位,經過初態轉換,16輪循環加密,終態轉換,最終每個64位的塊都會被加密成一個64位的密文塊,將得到的密文塊拼起來,得到的就是最終加密后的結果。

在這里插入圖片描述

    def encode(self, enter: str, key: str):result = ""# 將輸入的字符串處理為長度為64的塊blocks = self.processing_encode_input(enter)for block in blocks:# 對每一塊進行初態置換irb_result = self._init_replace_block(block)# 對每一塊進行16輪循環加密block_result = self.iteration(irb_result, key, is_decode=False)# 對每一塊進行終態置換block_result = self._end_replace_block(block_result)# 返回16進制形式的密文串result += str(hex(int(block_result.encode(), 2)))return result

1. 明文數據處理processing_encode_input

首先需要將字符串的明文轉換為二進制,按64位一組,分成若干組,如果不夠64位,就補零。

    from bitarray import bitarray@staticmethoddef _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) % 64 != 0:for i in range(64 - len(bit_string) % 64):bit_string += '0'for i in range(len(bit_string) // 64):result.append(bit_string[i * 64: i * 64 + 64])# print(f"轉換為二進制后的初始明文: {result}")return result

2. 初態轉換

初態轉換是將初始的64位塊按照 【IP置換表】的規則重新排序

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 置換表中每一位的意思是:將原來第i位的元素填充到這,如第一個58就表示把原來比特串中第58位放在新串的第1位,第二個50表示把原來比特串的第50位放在新串的第2位…

    @staticmethoddef replace_block(block: str, replace_table: tuple) -> str:"""對單個塊進行置換Args:block: str, 要進行轉換的64位長的01字符串replace_table: 轉換表Return:返回轉換后的字符串"""result = ""for i in replace_table:try:result += block[i - 1]except IndexError:print(i)print(f"block= {block}, len={len(block)}")raisereturn resultdef _init_replace_block(self, block: str):"""對一個塊進行初態置換"""replace_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)return self.replace_block(block, replace_table)

3. 16輪循環加密iteration

在這里插入圖片描述

每一輪循環加密的過程為:

  1. 將初態置換后或上一次循環后得到的64位塊分成左右各32位的子塊Left盒Right
  2. Right經過f函數轉換后得到一個32位的串,這個串與Left做異或后得到下一輪循環的Right
  3. 將這一輪原視的Right作為下一輪的Left
  4. 拼接Left盒Right,進行下一輪循環
    def iteration(self, block: str, key: str) -> str:for i in range(16):# 分成左右兩個子塊left, right = block[0: 32], block[32: 64]# 將這一輪原視的Right作為下一輪的Leftnext_left = right# f函數f_result = self._f_function(right, i)# f函數的輸出與left做異或得到下一輪的rightright = self._not_or(left, f_result)# 拼接,準備進行下一輪block = next_left + rightreturn block[32:] + block[:32]
  • 在最后一輪循環加密之后,left盒right是相反的,所以進行終態置換之前要換過來

3.1 f函數

在這里插入圖片描述

f函數有三部分組成:

  1. 拓展置換
  2. S盒置換
  3. P盒置換
    def _f_function(self, right: str, num: int):# 拓展置換right = self.block_extend(right)# S盒置換sbc_result = self.s_box_compression(num, right)# P盒置換return self.p_box_replacement(sbc_result)
3.1.1 拓展置換

拓展置換的目的是將一個32位的串根據【拓展置換表】轉換為48位,其實就是重復其中的某些位,達到混淆的目的。具體就是將32位的數據分成4*8小塊,每個小塊拓展為6位。

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

拓展置換表中,每一行代表拓展后的一個小塊,內部數字表示原來子塊中01的位置,其實就是在每一個小塊前面加上前一個小塊的最后一個字符,后面加上下一個小塊的第一個字符,比如有三個小塊:

0 1 0 0     1 0 1 1     1 0 0 1

那么第二個小塊拓展之后就是

0 1 0 1 1 1
    @staticmethoddef block_extend(block: str) -> str:"""拓展置換"""extended_block = ""extend_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)for i in extend_table:extended_block += block[i - 1]return extended_block
3.1.2 S盒置換

在這里插入圖片描述

S盒置換有兩步:

  1. 與密鑰keyi{key}_ikeyi?做異或
  2. S盒壓縮
    def s_box_compression(self, num: int, block48: str) -> str:"""對經過拓展置換后的48位01串進行S盒壓縮Args:num: 第幾次迭代block48: rightReturn:返回經過S盒壓縮后的32位01字符串"""# 與密鑰key做異或result_not_or = self._not_or(block48, self.child_keys[num])# S盒壓縮return self._s_box_replace(result_not_or)
密鑰keyi{key}_ikeyi?的獲得

在這里插入圖片描述

DES的原始密鑰是一個64位的01串,其中8,16, 24, 32, 40, 48,56, 64位作為奇偶檢驗位,通過密鑰轉換去除,實際加密中使用的只有56位,這56位的密鑰經過密鑰旋轉置換選擇會產生16個48位的子密鑰,所以每次循環加密用到的子密鑰都是不同的。

密鑰轉換的目的是將64位原始密鑰轉換為56位的密鑰,并進行一次置換

  • 依照的表是密鑰轉換表

    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
    
  • 代碼實現:

        def key_conversion(self, key):"""將64位原始密鑰轉換為56位的密鑰,并進行一次置換"""first_key = keykey_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)
    

密鑰旋轉:是為了保證16個子密鑰各不相同。具體做法是將56位密鑰分成兩個28位的子串,然后將這兩個子串進行循環旋轉,具體規則依照DesRotations

Round12345678910111213141516
Rotations1122222212222221
  • Round表示第幾輪旋轉,也就是第幾個key
  • Rotations表示旋轉次數
  • 除了第1, 2, 9, 16個key旋轉1位,其他都旋轉兩位

  • 每次旋轉是相對于上一次的結果而言的,比如第三個子密鑰就是原視的兩個28位串向左旋轉4位得到的

  • 代碼實現

        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
    

置換選擇:密鑰旋轉之后拼接得到一個56位的串,置換選擇可以選擇其中48位作為最終的keyi{key}_ikeyi?,置換選擇依照置換選擇表

  • 置換選擇表

    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  
    
  • 代碼實現

        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))
    
S盒壓縮

密鑰keyi{key}_ikeyi?與拓展置換后的right做異或后得到一個48位的串,這個串必須壓縮成32位才能作為下一輪的left。把這個48位的串分成8組,每組六位,壓縮就是要把6位變成4位,這里用到了8張 4*16 的【S盒壓縮表】

s_box1 = [[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],
],
s_box2 = [[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],
],
s_box3 = [[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],
],
s_box4 = [[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],
],
s_box5 = [[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],
],
s_box6 = [[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],
],
s_box7 = [[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],
],
s_box8 = [[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],
]

具體做法是:

將經過拓展置換后得到的48位串與48位密鑰做異或,得到48位密文串,每6個分一組,分8組,如第二組是111011就查找把第一位與最后一位取出得到11,轉換為十進制3作為行號,中間四位1101轉換為十進制13作為列號,查找s_box2的3行13列得到9,將9轉換為二進制為1001就是這6為密文壓縮后的結果,其他一樣,最終會輸出32位密文串。

代碼實現

    def _s_box_replace(self, block48: str) -> str:"""S盒置換,將48位的輸入轉換為32位輸出"""s_box_table = (((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),))result = ""for i in range(8):row_bit = (block48[i * 6] + block48[i * 6 + 5]).encode("utf-8")line_bit = (block48[i * 6 + 1: i * 6 + 5]).encode("utf-8")row = int(row_bit, 2)line = int(line_bit, 2)# print(f"第{row}行, 第{line}列")data = s_box_table[i][row][line]no_full = str(bin(data))[2:]while len(no_full) < 4:no_full = '0' + no_fullresult += no_fullreturn result
2.1.3 P盒置換

p盒置換作用也是為了混淆,用到了【P盒置換表】,原理與其他置換一樣

    def p_box_replacement(self, block32: str) -> str:"""P盒置換Return:返回經過P盒置換后的32位01串"""p_box_replace_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,)return self.replace_block(block32, p_box_replace_table)

4. 終態置換

與初態置換一樣, 只不過使用的置換表不一樣而已

  • 終態置換表
 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
  • 代碼實現
    def _end_replace_block(self, block: str) -> str:"""對某一個塊進行終態轉換"""replace_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)return self.replace_block(block, replace_table)

解密

解密使用與加密相同的算法,只不過使用子密鑰的順序不同而已,加密過程第一輪循環使用key1key_1key1?,解密過程第一輪循環使用key16key_{16}key16?,可以在循環加密處添加一個標志位完成

分組模式

明文可能被轉換為多個64位的塊,如果將每個塊單獨加密,后將所有塊加密后的結果簡單拼接起來構成最終密文,這樣的模式叫做ECB(電碼本模式),這種模式簡單, 但安全性不高,如果將上一個塊的加密后的結果與這個塊的原視數據做異或后再加密的模式叫做CBC(分組鏈接模式),還有CFBOFB

  • CBC模式下DES的加解密流程
    在這里插入圖片描述

完整代碼

# __author: Junebao
# data:2020/3/9from bitarray import bitarrayclass MyDES:def __init__(self):self.child_keys = []@staticmethoddef _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 _str_to__fixed_len_bit(self, s: str, length: int) -> str:"""將字符串轉變為固定長度的01字符串:param s: 要轉換的字符串:param length: 目標長度:return: 長度為length的01字符串"""bit_iv = self._bit_encode(s)while len(bit_iv) < length:bit_iv += '0'return bit_iv[: length]@staticmethoddef _bit_decode(s: list):return ''.join([chr(i) for i in [int(b, 2) for b in s]])@staticmethoddef _negate(s: str):result = ""try:for i in s:result += '0' if i == '1' else '1'return resultexcept:print("密鑰錯誤")raise@staticmethoddef _replace_block(block: str, replace_table: tuple) -> str:"""對單個塊進行置換Args:block: str, 要進行轉換的64位長的01字符串replace_table: 轉換表Return:返回轉換后的字符串"""result = ""for i in replace_table:try:result += block[i - 1]except IndexError:print(i)# print(f"block= {block}, len={len(block)}")raisereturn resultdef _processing_encode_input(self, enter: str) -> list:"""將輸入的字符串轉換為二進制形式,并沒64位為一組進行分割"""result = []bit_string = self._bit_encode(enter)# 如果長度不能被64整除,就補零if len(bit_string) % 64 != 0:for i in range(64 - len(bit_string) % 64):bit_string += '0'for i in range(len(bit_string) // 64):result.append(bit_string[i * 64: i * 64 + 64])# print(f"轉換為二進制后的初始明文: {result}")return result@staticmethoddef _processing_decode_input(enter: str) -> list:result = []try:input_list = enter.split("0x")[1:]int_list = [int("0x" + i, 16) for i in input_list]for i in int_list:bin_data = str(bin(i))[2:]while len(bin_data) < 64:bin_data = '0' + bin_dataresult.append(bin_data)return resultexcept Exception as e:raisedef _key_conversion(self, key: str):"""將64位原始密鑰轉換為56位的密鑰,并進行一次置換"""key = self._bit_encode(key)while len(key) < 64:key += '0'first_key = key[:64]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)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_spindef _key_selection_replacement(self, key: str):"""通過選擇置換得到48位的子密鑰"""# 先置空self.child_keys = []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))def _init_replace_block(self, block: str):"""對一個塊進行初態置換"""replace_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)return self._replace_block(block, replace_table)def _end_replace_block(self, block: str) -> str:"""對某一個塊進行終態轉換"""replace_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)return self._replace_block(block, replace_table)@staticmethoddef _block_extend(block: str) -> str:"""拓展置換"""extended_block = ""extend_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)for i in extend_table:extended_block += block[i - 1]return extended_block@staticmethoddef _not_or(a: str, b: str) -> str:"""對兩個01字符串做異或"""result = ""size = len(a) if len(a) < len(a) else len(b)for i in range(size):result += '0' if a[i] == b[i] else '1'return resultdef _s_box_replace(self, block48: str) -> str:"""S盒置換,將48位的輸入轉換為32位輸出"""s_box_table = (((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),))result = ""for i in range(8):row_bit = (block48[i * 6] + block48[i * 6 + 5]).encode("utf-8")line_bit = (block48[i * 6 + 1: i * 6 + 5]).encode("utf-8")row = int(row_bit, 2)line = int(line_bit, 2)# print(f"第{row}行, 第{line}列")data = s_box_table[i][row][line]no_full = str(bin(data))[2:]while len(no_full) < 4:no_full = '0' + no_fullresult += no_fullreturn resultdef _s_box_compression(self, num: int, block48: str) -> str:"""對經過拓展置換后的48位01串進行S盒壓縮,有兩部:1. 與key做異或2. 根據S盒壓縮表經48位壓縮為36位Args:num: 第幾次迭代block48: rightReturn:返回經過S盒壓縮后的32位01字符串"""result_not_or = self._not_or(block48, self.child_keys[num])# print(f"與key 做異或后的結果{result_not_or}")return self._s_box_replace(result_not_or)def _p_box_replacement(self, block32: str) -> str:"""P盒置換Return:返回經過P盒置換后的32位01串"""p_box_replace_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,)return self._replace_block(block32, p_box_replace_table)def _f_function(self, right: str, is_decode: bool, num: int):right = self._block_extend(right)if is_decode:sbc_result = self._s_box_compression(15 - num, right)else:sbc_result = self._s_box_compression(num, right)# print(f"s盒壓縮后的結果:{sbc_result}")return self._p_box_replacement(sbc_result)def _iteration(self, block: str, key: str, is_decode: bool) -> str:self._key_selection_replacement(key)for i in range(16):left, right = block[0: 32], block[32: 64]next_left = rightf_result = self._f_function(right, is_decode, i)right = self._not_or(left, f_result)block = next_left + rightreturn block[32:] + block[:32]def encode(self, enter: str, key: str):result = ""blocks = self._processing_encode_input(enter)for block in blocks:irb_result = self._init_replace_block(block)block_result = self._iteration(irb_result, key, is_decode=False)block_result = self._end_replace_block(block_result)result += str(hex(int(block_result.encode(), 2)))return resultdef encode_by_cbc(self, enter: str, des_key: str, iv: str):"""使用 CBC 模式進行 DES加密:param enter: 明文:param des_key: 密鑰:param iv: CBC模式中的因子:return: 加密后的十六進制格式密文串"""bit_iv = self._str_to__fixed_len_bit(iv, 64)result = ""blocks = self._processing_encode_input(enter)previous = bit_ivfor block in blocks:block = self._not_or(block, previous)irb_result = self._init_replace_block(block)block_result = self._iteration(irb_result, des_key, is_decode=False)block_result = self._end_replace_block(block_result)previous = block_resultresult += str(hex(int(block_result.encode(), 2)))return resultdef decode(self, cipher_text: str, key: str):result = []blocks = self._processing_decode_input(cipher_text)for block in blocks:irb_result = self._init_replace_block(block)block_result = self._iteration(irb_result, key, is_decode=True)block_result = self._end_replace_block(block_result)for i in range(0, len(block_result), 8):result.append(block_result[i: i+8])return self._bit_decode(result)def decode_by_cbc(self, cipher_text: str, des_key: str, iv: str):bit_iv = self._str_to__fixed_len_bit(iv, 64)result = []blocks = self._processing_decode_input(cipher_text)previous = bit_ivfor block in blocks:irb_result = self._init_replace_block(block)block_result = self._iteration(irb_result, des_key, is_decode=True)block_result = self._end_replace_block(block_result)block_result = self._not_or(block_result, previous)previous = blockfor i in range(0, len(block_result), 8):result.append(block_result[i: i+8])return self._bit_decode(result)if __name__ == '__main__':key = "hahahha"iv = "this is iv"md = MyDES()des_encode = md.encode("junebao.top", key)print("DES加密后的數據為:" + des_encode)print(f"解密出的數據為:" + md.decode(des_encode, key))cbc_encode = md.encode_by_cbc('http://blog.junebao.top', des_key=key, iv=iv)print(f"CBC mode encryption: {cbc_encode}")print(f"CBC mode decrypt: {md.decode_by_cbc(cbc_encode, des_key=key, iv=iv)}")

結果:

在這里插入圖片描述

參考

https://blog.csdn.net/wowocpp/article/details/80132097
https://www.bilibili.com/video/av75630674?t=133&p=7
https://blog.csdn.net/weixin_42940826/article/details/83687007?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457490.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457490.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457490.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python按身高體重排隊_LeetCode-python 406.根據身高重建隊列

題目鏈接難度&#xff1a;中等 類型&#xff1a; 數組假設有打亂順序的一群人站成一個隊列。 每個人由一個整數對(h, k)表示&#xff0c;其中h是這個人的身高&#xff0c;k是排在這個人前面且身高大于或等于h的人數。 編寫一個算法來重建這個隊列。注意&#xff1a;總人數…

遠程連接mysql數據庫,1130問題

遠程或使用非127.0.0.1和localhost地址連接時&#xff0c;出現代號為1130問題&#xff0c; ERROR 1130: Host 192.168.2.159 is not allowed to connect to this MySQL server 猜想這是沒有授權&#xff0c;將mysql數據庫中user表中host列的localhost改為%&#xff0c;重新啟動…

華為手機充滿有提醒嗎_2020手機充電速度排名:最快21分鐘充滿,華為第15名

5G手機扎堆出現&#xff0c;中國5G基站數量也是不斷增多&#xff0c;中國移動曾經表態&#xff0c;2020年底將會在全國地級市覆蓋5G網絡&#xff0c;全民5G時代終于到來&#xff01;從目前國內手機出貨量數據來看&#xff0c;5G手機占比已經達到了六成以上&#xff0c;國產5G手…

關于移動手機端富文本編輯器qeditor圖片上傳改造

日前項目需要在移動端增加富文本編輯&#xff0c;上網找了下&#xff0c;大多數都是針對pc版的&#xff0c;不太兼容手機&#xff0c;當然由于手機屏幕小等原因也限制富文本編輯器的眾多強大功能&#xff0c;所以要找的編輯器功能必須是精簡的。 找了好久&#xff0c;發現qedit…

【python】生成器

生成器 直接總結 創建生成器的方法 生成器表達式&#xff1a;(i for i in [1, 2])yield: 函數中出現yield這個函數就是生成器&#xff0c;函數&#xff08;生成器&#xff09;執行到yield時會返回yield后面的值&#xff0c;并暫停&#xff0c;知道下次被喚醒后會從暫停處接著…

python redis 性能測試臺_Redis性能測試

Redis 性能測試Redis 性能測試是通過同時執行多個命令實現的。Redis性能測試主要是通過src文件夾下的redis-benchmark來實現(Linux系統下)語法redis 性能測試的基本命令如下&#xff1a;redis-benchmark [option] [option value]實例以下實例同時執行 10000 個請求來檢測性能&a…

Java IO 系統

Java IO系統 File類 用來處理文件目錄&#xff0c;既可以代表一個特定文件的名稱&#xff0c;也可以代表一組文件的名稱&#xff0c;如果代表的是一個文件組&#xff0c;可以調用File.list()方法返回一個字符數組。 list()不傳遞任何參數時返回該目錄下所有文件或文件名的字…

Linux Crontab 任務管理工具命令以及示例

Crontab 是 Linux 平臺下的一款用于循環執行例行任務的工具,Linux 系統由 cron (crond) 這個系統服務來控制任務 , Linux系統本來就有很多的計劃任務需要啟動 , 所以這個系統服務是默認開機啟動的 。 Linux 為使用者提供的計劃任務的命令就是 Crontab Crontab 是 Linux 下用來周…

Linux 網絡編程詳解一(IP套接字結構體、網絡字節序,地址轉換函數)

IPv4套接字地址結構 struct sockaddr_in {uint8_t sinlen;&#xff08;4個字節&#xff09;sa_family_t sin_family;&#xff08;4個字節&#xff09;in_port_t sin_port;&#xff08;2個字節&#xff09;struct in_addr sin_addr;&#xff08;4個字節&#xff09;char sin_zer…

地籍cad的lisp程序大集合_AutoCAD-LISP程序100例

{:soso_e179:}AutoCAD-LISP程序100例.JPG (143.82 KB, 下載次數: 28)2011-10-18 14:42 上傳有說明很好&#xff01;頂如果您使用 AutoCAD,下面的內容對您一定有幫助。在某些方面能大大提高您的工作效率。下面的程序均以源程序方式給出&#xff0c;您可以使用、參考、修改它。bg…

javascript中數組的22種方法

前面的話數組總共有22種方法&#xff0c;本文將其分為對象繼承方法、數組轉換方法、棧和隊列方法、數組排序方法、數組拼接方法、創建子數組方法、數組刪改方法、數組位置方法、數組歸并方法和數組迭代方法共10類來進行詳細介紹對象繼承方法數組是一種特殊的對象&#xff0c;繼…

javascript/jquery高度寬度詳情解說分析

為什么80%的碼農都做不了架構師&#xff1f;>>> 一、window對象表示瀏覽器中打開的窗口 二、window對象可以省略 一、document對象是window對象的一部分 二、瀏覽器的HTML文檔成為Document對象 window.location和document.location window對象的location屬性引用的…

農用地包括哪些地類_土地地類一覽表

一級類二級類三級類含義編號三大類名稱編號名稱編號名稱1農用地指直接用于農業生產的土地&#xff0c;包括耕地&#xff0c;園地&#xff0c;林地&#xff0c;牧草地及其他的農業用地11耕地指種植農作物、土地&#xff0c;包括熟地、新開發復墾整理地&#xff0c;休閑地、輪歇地…

紅黑樹插入時的自平衡

紅黑樹插入時的自平衡 紅黑樹實質上是一棵自平衡的二叉查找樹&#xff0c;引入帶顏色的節點也是為了方便在進行插入或刪除操作時&#xff0c;如果破壞了二叉查找樹的平衡性能通過一系列變換保持平衡。 紅黑樹的性質 每個節點要么是紅色&#xff0c;要么是黑色根節點必須是黑…

說一下自己對于 Linux 哲學的理解

查閱了一些資料&#xff0c;官方的哲學思想貌似是&#xff1a; 一切皆文件由眾多單一目的的小程序&#xff0c;一個程序只實現一個功能&#xff0c;多個程序組合完成復雜任務文本文件保存配置信息盡量避免與用戶交互什么&#xff0c;你問我的理解&#xff1f;哲學思想&#xff…

UWP學習記錄

微軟{X:Bind}、{Binding}資料網站 &#xff1a; https://msdn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension在View的ItemTemplate中綁定ViewModel的方法&#xff1a;1 <ItemsControl Name"XX" ItemsSource"{x:Bind VM.XXModels,ModeOne…

dw1000信標碼_DW1000方案工牌型UWB標簽,助力10厘米高精度室內定位!

DW1000方案工牌型UWB標簽&#xff0c;助力10厘米高精度室內定位&#xff01;發布日期&#xff1a;2019-04-01 瀏覽次數&#xff1a;244次微能信息(95power)推出一款工牌型UWB標簽VDU1510 &#xff0c;廣泛應用于超寬帶UWB定位系統&#xff0c;最高可實現10cm高精度人員定位。工…

【Java】HashMap源碼(1.7)

Life is not a ridiculous number of life, the meaning of life lies in life itself HashMap源碼 散列集 數組和鏈表可以保持元素插入的順序&#xff0c;對數組來說&#xff0c;他的優點是擁有連續的存儲空間&#xff0c;因此可以使用元素下標快速訪問&#xff0c;但缺點在…

Docker 基本用法

1.安裝&#xff1a; wget http://mirrors.yun-idc.com/epel/6/i386/epel-release-6-8.noarch.rpm rpm -ivh epel-release-6-8.noarch.rpm yum install docker-io -y2.獲取鏡像 pull docker pull ubuntu docker pull ubuntu:14.043.運行這個鏡像&#xff0c;在其中運行bash應用…

畫刷的使用

1.畫刷的定義&#xff1a; HBRUSH hBrush; windows 自定義的畫刷&#xff1a; WHITE_BRUSH、LTGRAY_BRUSH、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH和NULL_BRUSH &#xff08;也叫HOLLOW_BRUSH&#xff09; 獲取方法如下&#xff1a; hBrush (HBRUSH) GetStockObject (GRAY_BR…