簡介
DES是分組密碼的一類,是一種對稱密碼技術,使用了Feistel的網絡結構,將明文分成多個等長模塊,使用確定的算法以及對稱並且相同的密鑰對明密文進行加解密。
算法流程
- 64位的明文經過初始置換而被重新排列,並將其分爲左右兩個分組L0和R0各32位。
- 在密鑰的參與下,最左右兩個分組進行16輪相同函數的迭代,每輪迭代都有置換和代換。注意最後一輪迭代的輸出爲64位。左半部分和右半部分不進行交換。
- 最後的預輸出再通過逆初始置換產生64位的密文。
- 加解密過程一樣,反過來即可,也就是祕鑰列表得倒過來。所以得注意一下。
核心代碼及算法分析
第一部經過分是明文經過IP置換的操作,這裏可以直接用一維數組去完成,這需要注意的是數組下標不要寫錯,會導致數組越界,最後一部分IP逆的那一部分也一樣的道理。
def ip_change(bin_str):
res = ""
for i in IP_table:
res += bin_str[i-1] #數組下標i-1
return res
#IP逆盒處理
def ip_re_change(bin_str):
res = ""
for i in IP_re_table:
res += bin_str[i-1]
return res
再下來就是經過16輪迭代的過程,每一步的迭代過程裏面又包含了F函數,還有密鑰的產生。
首先是一個大致的迭代過程,很清楚首先產生了16輪迭代的祕鑰,每一輪的迭代都有密鑰參與,並且通過切片完成了每一輪的左右分組,然後右邊的分組作爲了新的左邊,左邊的分組以及右邊的分組還有密鑰通過F函數的計算獲得新的右分組,最後一輪不做交換,這也就是我爲什麼只循環了15輪。
def des_encrypt_one(bin_message,bin_key): #64位二進制加密的測試
#bin_message = deal_mess(str2bin(message))
mes_ip_bin = ip_change(bin_message)
#bin_key = input_key_judge(str2bin(key))
key_lst = gen_key(bin_key)
mes_left = mes_ip_bin[0:32]
mes_right = mes_ip_bin[32:]
for i in range(0,15):
mes_tmp = mes_right
f_result = fun_f(mes_tmp,key_lst[i])
mes_right = str_xor(f_result,mes_left)
mes_left = mes_tmp
f_result = fun_f(mes_right,key_lst[15])
mes_fin_left = str_xor(mes_left,f_result)
mes_fin_right = mes_right
fin_message = ip_re_change(mes_fin_left + mes_fin_right)
return fin_message
再看看產生密鑰的關鍵代碼gen_key,傳進去的參數密鑰實際是64位的,但實際發揮作用的是56位,是因爲僅過了一次PC-1的置換,這也解釋了這段代碼爲什麼到後面切片的時候以28爲中心分左右。然後根據是第幾輪然後對左右分組的密鑰進行循環左移,出來的56位再經過一次置換生成48位的密鑰,最後用數組將所有密鑰都裝好。
def gen_key(key):
key_list = []
divide_output = change_key1(key)
key_C0 = divide_output[0:28]
key_D0 = divide_output[28:]
for i in SHIFT:
key_c = left_turn(key_C0,i)
key_d = left_turn(key_D0,i)
key_output = change_key2(key_c + key_d)
key_list.append(key_output)
return key_list
PC-1,PC-2的置換過程,跟IP置換差不多,都是利用了打表然後字符串拼接的方式實現
#祕鑰的PC-1置換
def change_key1(my_key):
res = ""
for i in PC_1:
res += my_key[i-1]
return res
#祕鑰的PC-2置換
def change_key2(my_key):
res = ""
for i in PC_2:
res += my_key[i-1]
return res
重點還有F函數的處理,也即是代碼裏面的fun_f,這裏面主要有四個步驟,分別是擴展置換,密鑰加,經過S盒的代換,最後經過了P盒的置換,最終把32位的輸入變成48位的輸出。E盒以及P盒的置換也是很簡單打好表然後用字符串拼接就好。關鍵是S盒的變換原理,6位的輸入4位的輸出,輸入前兩位作爲S盒橫座標,中間4位作爲列,但是我這裏是以bin輸出得注意位數不夠四位得補齊
# F函數的實現
def fun_f(bin_str,key):
first_output = e_key(bin_str)
second_output = str_xor(first_output,key)
third_output = s_box(second_output)
last_output = p_box(third_output)
return last_output
#E盒置換
def e_key(bin_str):
res = ""
for i in E:
res += bin_str[i-1]
return res
# S盒過程
def s_box(my_str):
res = ""
c = 0
for i in range(0,len(my_str),6):
now_str = my_str[i:i+6]
row = int(now_str[0]+now_str[5],2)
col = int(now_str[1:5],2)
num = bin(S[c][row*16 + col])[2:] #利用了bin輸出有可能不是4位str類型的值,所以纔有下面的循環並且加上字符0
for gz in range(0,4-len(num)):
num = '0'+ num
res += num
c += 1
return res
#P盒置換
def p_box(bin_str):
res = ""
for i in P:
res += bin_str[i-1]
return res
正確性
加密解密內容都會放到文件裏面,然後通過讀寫文件的方式將內容成功加解密,以"helloworld"爲例,能夠正確加解密