Symmetric Key Encryption DES

一、對稱加密 (Symmetric Key Encryption) 

對稱加密是最快速、最簡單的一種加密方式,加密(encryption)與解密(decryption)用的是同樣的密鑰(secret key)。對稱加密有很多種算法,由於它效率很高,所以被廣泛使用在很多加密協議的核心當中。自1977年美國頒佈DES(Data Encryption Standard)密碼算法作爲美國數據加密標準以來,對稱密碼體制迅速發展,得到了世界各國的關注和普遍應用。對稱密碼體制從工作方式上可以分爲分組加密和序列密碼兩大類。

對稱加密算法的優點:算法公開、計算量小、加密速度快、加密效率高。

對稱加密算法的缺點:交易雙方都使用同樣鑰匙,安全性得不到保證。此外,每對用戶每次使用對稱加密算法時,都需要使用其他人不知道的惟一鑰匙,這會使得發收信雙方所擁有的鑰匙數量呈幾何級數增長,密鑰管理成爲用戶的負擔。對稱加密算法在分佈式網絡系統上使用較爲困難,主要是因爲密鑰管理困難,使用成本較高。而與公開密鑰加密算法比起來,對稱加密算法能夠提供加密和認證卻缺乏了簽名功能,使得使用範圍有所縮小。

對稱加密通常使用的是相對較小的密鑰,一般小於256 bit。因爲密鑰越大,加密越強,但加密與解密的過程越慢。

分組密碼:也叫塊加密(block cyphers),一次加密明文中的一個塊。是將明文按一定的位長分組,明文組經過加密運算得到密文組,密文組經過解密運算(加密運算的逆運算),還原成明文組,有 ECB、CBC、CFB、OFB 四種工作模式。

序列密碼:也叫流加密(stream cyphers),一次加密明文中的一個位。是指利用少量的密鑰(制亂元素)通過某種複雜的運算(密碼算法)產生大量的僞隨機位流,用於對明文位流的加密。解密是指用同樣的密鑰和密碼算法及與加密相同的僞隨機位流,用以還原明文位流。

常用對稱加密算法包括 DES、3DES、AES

1. DES(Data Encryption Standard):數據加密標準,速度較快,適用於加密大量數據的場合。
2. 3DES(Triple DES):是基於DES,對一塊數據用三個不同的密鑰進行三次加密,強度更高。
3. AES(Advanced Encryption Standard):高級加密標準,是下一代的加密算法標準,速度快,安全級別高,支持128、192、256、512位密鑰的加密。

算法特徵
1. 加密方和解密方使用同一個密鑰。
2. 加密解密的速度比較快,適合數據比較長時的使用。
3. 密鑰傳輸的過程不安全,且容易被破解,密鑰管理也比較麻煩。

 

二、簡介對稱加密算法 Des

1、數據加密標準 Des

(1)Des 設計理念

Des 設計中使用了分組密碼設計的兩個原則:混淆(confusion)和擴散(diffusion),其目的是抗擊敵手對密碼系統的統計分析。混淆是使密文的統計特性與密鑰的取值之間的關係 儘可能複雜化,以使密鑰和明文以及密文之間的依賴性對密碼分析者來說是無法利用的。擴散的作用就是將每一位明文的影響儘可能迅速地作用到較多的輸出密文位中,以便在大量的 密文中消除明文的統計結構,並且使每一位密鑰的影響儘可能迅速地擴展到較多的密文位中,以防對密鑰進行逐段破譯。

2、Des 加密算法結構流程

 

      

 

3、Des 加密算法電子編碼本 ECB (Electronic Code Book,電子編碼本) 模式流程 

(1)ECB 模式 & 性能

ECB 模式是最簡單的加密模式,明文消息被分成固定大小的塊(分組),並且每個塊被單獨加密。每個塊的加密和解密都是獨立的,且使用相同的方法進行加密,所以可以進行並行計算,但是這種方法一旦有一個塊被破解,使用相同的方法可以解密所有的明文數據,安全性比較差。適用於數據較少的情形,加密前需要把明文數據填充到塊大小的整倍數。

ECB算法優點:
簡單、孤立,每個塊單獨運算。適合並行運算。傳輸錯誤一般隻影響當前塊。
ECB算法缺點:
同明文輸出同密文,可能導致明文攻擊。

(2)ECB 加密 & 解密流程

Encryption:

Decryption:

4、Des 分組加密所需參數 

(1)Key:64位主密鑰

(2)明文:64位的倍數

(3)密文:64位的倍數

(4)分組模式填充方式:PKCS5

(5)分組密碼工作模式:EBC模式

5、Des 加密過程

(1)初始置換(IP)

根據初始置換表,對相應明文位置上的二進制進行置換操作,即把64  位的數據塊的原第  58  位換到第一位,原第 50 位換到第二位.依此類推。目的在於打亂明文中各位的次序。

(2)子密鑰生成

 

                           

從用戶處取得一個 64 位長的密鑰key  ,去除 64 位密鑰中作爲奇偶校驗位的第 8、16、24、32、40、48、56、64 位,剩下的 56 位作爲有效輸入密鑰。把生成的 56 位輸入密鑰分成均等的 A,B 兩部分,每部分爲 28 位,使用置換選擇 1 對剩下的 58 位打亂,輸出左 28 位 C 和右 28 位 D。兩個部分都進行向左移位,移位後的兩部分數據有兩個作用。第一輸出子密鑰,每 i 輪兩部分合在一起進行進行置換選擇 2 得到迭代運算的第 i 個子密鑰,第二作爲下一輪子密鑰運算。總共 16 輪運算(i=1,2,9,6 左移 1 位,其餘 2 位)。

(3)16 輪迭代運算 (Des 核心)

                     

首先將二進制分爲兩個 32 位的部分:left 和 right。保持 left 不變,根據擴展置換表把 right 由 32 位擴展成 48 位。把擴展後的 48 位 right 與第 i 次迭代生成的 48 位子密鑰按位異或運算,形成一個新的 48 位的 right。然後與主密鑰生成的 48 位子密鑰異或操作,然後進行 S 盒代換,得到一個 32 位的二進制數據,將數據進行 P 盒置換後,與 left 進行異或操作,結果作爲下一輪迭代運算的 right 部分。上一輪 right 部分作爲下一輪運算的 left 部分。第 16 次迭代不交換兩者的數值。

(4)初始逆置換

16輪迭代運算後,依據初始逆置換表,對相應位置的二進制數進行置換操作。最後得到密文。

6、Des 解密過程

Des 算法是對稱的,既可用加密又可用於解密,只不過在16次迭代中使用的密鑰次序正好相反。解密時,第一次迭代使用子密鑰K16,依次類推。

7、分組密碼工作方式

ECB,將明文消息分成 n 個 m  bit 組(m 通常爲 64),如果長度不是 m 整數倍,則在明文末尾進行填充 (本次實驗採用PKCS5)

 

三、實現對稱加密算法 Des 

1、語言 & 環境

(1)語言

Python

(2)環境

Python版本:python 3.7

Python工具:PyCharm Professional

2、操作流程

(1)在 < text.txt > 文件中讀取需要加密的文本
(2)在 < key.txt > 文件中寫入隨機產生固定長度的Key
(3)在 < ciphertext.txt > 文件中寫入DES加密、Base64編碼後的數據
(4)在 < plaintext.txt > 文件中寫入Base64解碼、DES解密後的數據

3、主要代碼

(1)Main 函數

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
 1     if __name__ == '__main__':
 2         key = getRandomString()
 3         with open('text.txt', 'r+') as fr:
 4             text = (fr.read())          # 從 'text.txt' 文件中讀取加密文本
 5         D = Des()
 6         C = (base64.b64encode((D.encrypt(key, text, True)).encode("utf8"))).decode()  # 加密
 7         C1 = (base64.b64decode(C)).decode()
 8         P = D.decrypt(key, C1, True)                # 解密
 9         with open('key.txt', 'w+') as fwk:          # 存儲密鑰
10             fwk.write(key)
11         with open('ciphertext.txt', 'w+') as fwc:   # 存儲密文
12             fwc.write(C)
13         with open('plaintext.txt', 'w+') as fwp:    # 存儲明文
14             fwp.writelines(P)
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

 (2)Encryption

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
1     def encrypt(self, key, text, padding):          # DES 加密函數
2         return self.run(key, text, ENCRYPT, padding)
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(3)Decryption

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
1     def decrypt(self, key, text, padding):          # DES 解密函數
2         return self.run(key, text, DECRYPT, padding)
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < <

(4)字符串和比特數組之間相互轉換

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
 1     def string_to_bit_array(text):             # 字符串-->bit數組
 2         array = list()
 3         for char in text:
 4             binval = binvalue(char, 8)         # 獲得每個字符的二進制
 5             array.extend([int(x) for x in list(binval)])
 6         return array
 7 
 8     def bit_array_to_string(array):            # bit數組-->字符串
 9         res = ''.join([chr(int(y, 2)) for y in [''.join([str(x) for x in bytes]) for bytes in nsplit(array, 8)]])
10         return res
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < <

(5)二進制處理

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
1     def binvalue(val, bitsize):              # 以給定大小的字符返回二進制值
2         binval = bin(val)[2:] if isinstance(val, int) else bin(ord(val))[2:]
3         if len(binval) > bitsize:
4             raise Exception("binary value larger than the expected size")
5         while len(binval) < bitsize:
6             binval = "0" + binval
7         return binval
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < <

(6)列表劃分

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
1     def nsplit(s, n):                     # 將列表拆分爲大小爲'n'的子列表
2         return [s[k:k + n] for k in range(0, len(s), n)]
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(7)獲取隨機固定長度序列 Key

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
1     def getRandomString(slen=8):        # 獲得key的隨機序列
2         return ''.join(random.sample(string.ascii_letters + string.digits, slen))
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(8)初始化 Des 類

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
1     def __init__(self):
2         self.password = None            # 存放初始key
3         self.text = None                # 存放明文
4         self.keys = list()              # 存放key值列表集合
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(9)PKCS5 模式 數據填充

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
1     def addPadding(self):  # PKCS5 進行數據填充,不管是否是BlockSize的整數倍都需要進行填充
2         pad_len = 8 - (len(self.text) % 8)
3         self.text += pad_len * chr(pad_len)
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(10)數據填充移除

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
1     def removePadding(self, data):                     # 刪除純文本的填充
2         pad_len = ord(data[-1])
3         return data[:-pad_len]
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(11)獲取 Key 值集合列表

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
1     def generatekeys(self):                       # 統計計算所有key值的算法
2         self.keys = []
3         key = string_to_bit_array(self.password)
4         key = self.permut(key, CP_1)              # 置換選擇1 初始化key 64bit-->56bit
5         g, d = nsplit(key, 28)                    # 分片 (g->LEFT),(d->RIGHT)
6         for i in range(16):                       # 16輪循環
7             g, d = self.shift(g, d, SHIFT[i])       # (g->LEFT),(d->RIGHT)分別進行移位操作
8             tmp = g + d                             # 合併 28bit+28bit-->56bit
9             self.keys.append(self.permut(tmp, CP_2))     # 置換選擇2 56bit-->48bit
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(12)Key 值移位函數

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
1     def shift(self, g, d, n):                     # 每輪key值產生所需的函數
2         return g[n:] + g[:n], d[n:] + d[:n]
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(13)基本置換 擴展置換 壓縮置換

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
1     def permut(self, block, table):              # 置換(本程序中充當基本置換、壓縮置換的角色)
2         return [block[x - 1] for x in table]
3 
4     def expand(self, block, table):              # 擴展置換
5         return [block[x - 1] for x in table]
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(14)自定義 XOR 函數

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
1     def xor(self, t1, t2):                      # 應用xor並返回結果列表
2         return [x ^ y for x, y in zip(t1, t2)]
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

(15)S 盒代換

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
 1     def substitute(self, d_e):                           # S盒代換
 2         subblocks = nsplit(d_e, 6)                       # 將位數組分割爲6位的子列表
 3         result = list()
 4         for i in range(len(subblocks)):                  # 遍歷子列表
 5             block = subblocks[i]
 6             row = int(str(block[0]) + str(block[5]), 2)  # 得到第一位和最後一個位表示的行
 7             column = int(''.join([str(x) for x in block[1:][:-1]]), 2) #得到第二、三、四、五位表示的列
 8             val = S_BOX[i][row][column]                # 取爲本輪分配的SBOX[i]中的值
 9             bin = binvalue(val, 4)                     # 將值轉換爲二進制
10             result += [int(x) for x in bin]            # 將二進制值添加到結果列表中
11         return result
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < <

(16)16輪運算核心

> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
 1     for block in text_blocks:               # 遍歷所有數據塊
 2         block = string_to_bit_array(block)
 3         block = self.permut(block, IP)      # 數據塊的初始置換
 4         g, d = nsplit(block, 32)            # 數據塊分片 g(LEFT), d(RIGHT)
 5         tmp = None
 6         for i in range(16):                 # 16輪循環
 7             d_e = self.expand(d, E)         # d(RIGHT)的擴展 32bit-->48bit
 8             if action == ENCRYPT:
 9                 tmp = self.xor(self.keys[i], d_e)
10             else:
11                 tmp = self.xor(self.keys[15 - i], d_e)  # 如果是解密的話先使用最後的key
12             tmp = self.substitute(tmp)                  # S盒代換 48bit-->32bit
13             tmp = self.permut(tmp, P)                   # P盒置換
14             tmp = self.xor(g, tmp)
15             g = d
16             d = tmp
17         result += self.permut(d + g, IP_1)              # 數據塊的初始逆置換
18     final_res = bit_array_to_string(result)
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 

4、數據測試

(1)測試結果

(2)在 < text.txt > 文件中讀取需要加密的文本

(3)在 < key.txt > 文件中寫入隨機產生固定長度的Key

(4)在 < ciphertext.txt > 文件中寫入DES加密、Base64編碼後的數據

(5)在 < plaintext.txt > 文件中寫入Base64解碼、DES解密後的數據

5、該項目所有代碼文件上傳至 Github 

(1)GitHub 主頁

https://github.com/Qftm

(2)Des 項目地址

https://github.com/Qftm/Symmetric_Key_Encryption_DES

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章