python DES算法的原理及实现

最近在完成电子商务安全的一个小作业,实现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模式,并且该代码不具有异常处理等措施,十分简陋,以后有机会会改进的。
下面是我在完成算法时参考的两篇博客:
按着这个了解原理并一步步敲的
按照这个调试各个模块运行的结果是否正确

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值