最近在完成电子商务安全的一个小作业,实现DES算法,经过一番查阅资料以及三个晚上的爆肝,终于完成了任务,下面用简单的文字描述一下这个过程。
1. 把明文按照一张表置换位置。
2. 把初始密钥按照一张表置换位置。
3. 进入16轮的迭代,每一轮迭代首先根据轮数与移动位数所对应的表生成子密钥。如果是加密的话,就是密
钥按照表左移指定位数,解密就是按照表右移指定位数。
4. 得到每一轮的子密钥过后,将要加密数据的右边按照一张表扩展成48位,然后把这个扩展的数据与该轮的
子密钥进行异或处理,再将结果输入S盒,由于6进4出,所以S盒过后得到32位的数据。
5. S盒过后得到的数据再进入P盒,按照一张表置换位置,再将结果与数据的左半部分异或,之后第一轮迭代
过后的数据就等于数据的右半部分加上异或结果
6. 在完成16次迭代过后再按照一张表进行逆置换,得到最终的结果(即加密或解密后的结果)
下面来介绍一下我的具体实现,代码使用python实现的:
Input:64位的二进制表示的明文和初始密钥以及模式,若为加密,则模式参数为E,解密为D。
Output:显示原文和加密结果。
在我的例子中,我的明文和初始密钥均为’0123456789ABCDEF’,加密过后的密文为’56cc09e7cfdc4cef’,在完成加密过后,再用加密过后的密文与初始密钥进行解密,得到的解密结果为’0123456789ABCDEF’,故验证了其正确性。
下面是代码:
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 4 21:38:22 2019
@author: zhhandsome
"""
def hex2bin(text):
ret = ''
for i in text:
tmp = bin(int(i, 16))[2:]
ret += '0'*(4-len(tmp)) + tmp
return ret
def bin2hex(text):
ret = ''
for i in range(0, len(text), 4):
tmp = text[i:i+4]
ret += hex(int(tmp, 2))[2:]
return ret
class DES_ECB:
def __init__(self, text, key, mode):
self.original_text = text
self.text = text
self.key = key
self.mode = mode
self.ring_shift_left = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]
self.ring_shift_right = [0,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]
self.PC_2 = [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]
self.S_box = [[] for i in range(8)]
self.S_box[0] = [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]
self.S_box[1] = [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]
self.S_box[2] = [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]
self.S_box[3] = [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]
self.S_box[4] = [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]
self.S_box[5] = [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]
self.S_box[6] = [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]
self.S_box[7] = [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]
self.P_box = [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]
#初始置换,将64位的明文按照特定顺序置换
def text_initial_permutation(self):
index = 0
D = ['' for i in range(64)]
for i in range(58, 65, 2):
for j in range(i, i-57, -8):
D[index] = self.text[j-1]
D[index+32] = self.text[j-2]
index += 1
self.text = ''.join(D)
#密钥置换,64位密钥变成56位后置换
def key_initial_permutation(self):
index = 0
permutationed_key = ['' for i in range(56)]
for i in [57, 58, 59, 60, 63, 62, 61, 28]:
if i not in [28, 60]:
count = 8
else:
count = 4
for j in range(count):
permutationed_key[index] = self.key[i-1]
index += 1
i -= 8
self.key = ''.join(permutationed_key)
#根据给定的轮数生成子密钥并返回
def generate_sub_key(self, rounds):
left = self.key[0:28]
right = self.key[28:56]
if self.mode == 'E':
shift_left_bits = self.ring_shift_left[rounds-1]
left = left[shift_left_bits:] + left[:shift_left_bits]
right = right[shift_left_bits:] + right[:shift_left_bits]
else:
shift_right_bits = self.ring_shift_right[rounds-1]
left = left[-shift_right_bits:] + left[:-shift_right_bits]
right = right[-shift_right_bits:] + right[:-shift_right_bits]
self.key = left + right
permutationed_sub_key = ['' for i in range(48)]
index = 0
for i in self.PC_2:
permutationed_sub_key[index] = self.key[i-1]
index += 1
return ''.join(permutationed_sub_key)
#扩展置换数据右半部分并返回
def expansion_permutation(self):
right = self.text[32:]
expansion_right = ['' for i in range(48)]
expansion_right[0] = right[-1]
expansion_right[-1] = right[0]
index = 1
count = 0
for i in range(1, 47):
expansion_right[i] = right[index-1]
count += 1
if count == 5:
index -= 1
count = -1
else:
index += 1
return ''.join(expansion_right)
#S盒变换,Rn扩展置换之后的48位与子密钥Kn异或以后输入S盒,将48位变成32位
def S_box_permutation(self, text, key):
xor_result = ''
for i in range(48):
xor_result += '0' if text[i]==key[i] else '1'
after_S_box_data = ''
for i in range(0, 48, 6):
block = xor_result[i:i+6]
row = int(block[0]+block[-1], 2)
colume = int(block[1:5], 2)
tmp = bin(self.S_box[i//6][16*row+colume])[2:]
after_S_box_data += '0'*(4-len(tmp)) + tmp
return after_S_box_data
#P盒置换,用S盒置换得到后的32位用于输入,与P盒置换后的结果与数据的64位左边异或,然后左右交换
def P_box_permutation(self, text):
after_P_box_data = ['' for i in range(32)]
index = 0
for i in range(32):
after_P_box_data[index] = text[self.P_box[i]-1]
index += 1
after_P_box_data = ''.join(after_P_box_data)
left = self.text[0:32]
xor_result = ''
for i in range(32):
xor_result += '0' if left[i]==after_P_box_data[i] else '1'
self.text = self.text[32:] + xor_result
#逆置换
def inverse_permutation(self):
self.text = self.text[32:] + self.text[0:32]
inverse_data = ['' for i in range(64)]
current = 39
count = 16
index = 0
while(count):
inverse_data[index] = self.text[current]
inverse_data[index+16] = self.text[current-2]
inverse_data[index+32] = self.text[current-4]
inverse_data[index+48] = self.text[current-6]
index += 1
if count%2 == 0:
current -= 32
else:
current += 40
count -= 1
if count == 8:
current = 38
self.text = ''.join(inverse_data)
#执行操作
def do_final(self):
self.text_initial_permutation()
self.key_initial_permutation()
for i in range(1, 17):
sub_key = self.generate_sub_key(i)
expansioned_right = self.expansion_permutation()
right_after_S_box = self.S_box_permutation(expansioned_right, sub_key)
self.P_box_permutation(right_after_S_box)
self.inverse_permutation()
print('原文:', bin2hex(self.original_text))
print('密文:', bin2hex(self.text))
return self.text
#初始明文
text = hex2bin('0123456789ABCDEF')
#初始密钥
key = hex2bin('0123456789ABCDEF')
des_encrypt = DES_ECB(text, key, 'E')
cipher_text = des_encrypt.do_final()
des_decrypt = DES_ECB(cipher_text, key, 'D')
des_decrypt.do_final()
严格地说,这应该属于ECB模式,并且该代码不具有异常处理等措施,十分简陋,以后有机会会改进的。
下面是我在完成算法时参考的两篇博客:
按着这个了解原理并一步步敲的
按照这个调试各个模块运行的结果是否正确