DES密码算法和python实现

1. 前言

        DES 算法是一种常见的分组加密算法,由IBM公司在1971年提出。DES 算法是分组加密算法的典型代表。其加密运算、解密运算使用相同的秘钥。

        DES 算法利用56+8奇偶校验位(第8,16,24,32,40,48,56,64)=64位的密钥对以64位为单位的块数据进行加解密。

        DES算法是以64位为一组分组加密的,所以当输入的明文长度,不满足64的整数倍时,需要涉及到数据的填充。

        DES算法将输入明文分为N个64位大小的分组,然后依次根据加密运算,生成N组加密后的密文 ,将生成的N组密文,就是我们要最终的成果——DES密文输出。

        包含DES算法在内的现代密码学知识可以查看以下博客

CISSP考试要求里的“应用密码学”内容辅助记忆趣味串讲_晓翔仔的博客-CSDN博客

2.  DES加密原理

2.1 初始置换

初始置换就是将明文M打乱重排序。并生成L0 , R0

2.2 生成子秘钥

DES加密的过程,明文M共经历了16次运算迭代,每次迭代的数据长度是48 ,因此我们需要16组48位的加密秘钥来进行加密。

        PC-1置换

        PC-2置换

2.3  迭代的过程

f函数

         f函数就是不断计算Li,Ri的过程,此过程包括四个部分:E盒置换、S盒置换、P盒置换、左右校验

2.4 逆置换

2.5 解密

        解密过程同加密过程,只不过是按照反向的次序。

2.6 数据填充

        当明文长度不为分组长度的整数倍时,需要在最后一个分组中填充一些数据使其凑满一个分组长度。

NoPadding
API或算法本身不对数据进行处理,加密数据由加密双方约定填补算法。例如若对字符串数据进行加解密,可以补充\0或者空格,然后trim

PKCS5Padding
加密前:数据字节长度对8取余,余数为m,若m>0,则补足8-m个字节,字节数值为8-m,即差几个字节就补几个字节,字节数值即为补充的字节数,若为0则补充8个字节的8
解密后:取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文。
加密字符串为为AAA,则补位为AAA55555;加密字符串为BBBBBB,则补位为BBBBBB22;加密字符串为CCCCCCCC,则补位为CCCCCCCC88888888。

PKCS7Padding
PKCS7Padding 的填充方式和PKCS5Padding 填充方式一样。只是加密块的字节数不同。PKCS5Padding明确定义了加密块是8字节,PKCS7Padding加密快可以是1-255之间。

2.7 加密模式

电子代码本(Electronic CodeBook, ECB)模式

        一般用途:加密少量数据,如秘钥和PIN值

密码分组链接(Cipher Block Chaini吨, CBC)模式

         一般用途:加密大型数据

密码回馈(Cipher FeedBack, CFB)模式

        一般用途:加密较小数据,单独加密每个位

输出回馈(Output FeedBack, OFB)模式

        特点:比OFB发生扩展错误的可能性小

计数(CounTeR, CTR)模式。

        特点:IV计数器,并行

参考

这篇博客将DES加密原理讲的通俗易懂,值得阅读。

DES加密算法原理及代码实现_des加密算法代码_better_hui的博客-CSDN博客

3. 代码实现

3.1 ECB和CBC模式的加解密代码

from pyDes import des, CBC, PAD_PKCS5
import binascii


def bytesToHexString(data):
    temp = []
    for i in data:
        temp.append('0x%02X' % i)
    return temp


"""
    DES-ECB 加密
    :param s: 原始字符串,密钥
    :return: 加密后字符串,16进制
    """


def des_encrypt(s, key):
    secret_key = key
    iv = secret_key
    k = des(secret_key)
    en = k.encrypt(s)
    return binascii.b2a_hex(en)


"""
    DES-ECB 解密
    :param s: 原始字符串,密钥
    :return: 解密后字符串,16进制
    """


def des_decrypt(s, key):
    secret_key = key
    iv = secret_key
    k = des(secret_key)
    en = k.decrypt(s)
    return binascii.b2a_hex(en)


"""
    DES-CBC 加密
    :param s: 原始字符串,密钥
    :return: 加密后字符串,16进制
    """


def des_cbc__encrypt(s, key, iv):
    secret_key = key

    k = des(secret_key, mode=CBC, IV=iv)
    en = k.encrypt(s)
    return binascii.b2a_hex(en)


"""
    DES-CBC 加密
    :param s: 原始字符串,密钥
    :return: 加密后字符串,16进制
    """


def des_cbc__decrypt(s, key, iv):
    secret_key = key

    k = des(secret_key, mode=CBC, IV=iv)
    en = k.decrypt(s)
    return binascii.b2a_hex(en)


if __name__ == '__main__':
    data = '1111111111111111'
    key = '1111111111111111'
    iv = '1111111111111111'  # iv 仅仅用于cbc模式,若iv设置为全0,则CBC模式的计算结果和ECB模式是一样的
    print("data:", data, "key:", key, "iv:", iv)
    print("des ecb encrypt result:", des_encrypt(bytes.fromhex(data), bytes.fromhex(key)))
    print("des ecb decrypt result:", des_decrypt(bytes.fromhex(data), bytes.fromhex(key)))
    print("des cbc encrypt result:",
          des_cbc__encrypt(bytes.fromhex(data), bytes.fromhex(key), bytes.fromhex(iv)))
    print("des cbc decrypt result:",
          des_cbc__decrypt(bytes.fromhex(data), bytes.fromhex(key), bytes.fromhex(iv)))

自测结果

data: 1111111111111111 key: 1111111111111111 iv: 1111111111111111
des ecb encrypt result: b'f40379ab9e0ec533'
des ecb decrypt result: b'237b2304c393d3ac'
des cbc encrypt result: b'82e13665b4624df5'
des cbc decrypt result: b'326a3215d282c2bd'

Process finished with exit code 0

3.2 一种应用场景下的DES解码编码python代码

已知:

1.使用DES ECB密码算法,秘钥已经获取到。

2. 获取到"明文前缀“+密文",都是十六进制表示,密文由"固定长度的固定位 + 时间戳+ crc"组成。crc 使用ccitt_false模式。

需要:

明文前缀不变,密文DES解码后,更新时间戳为最新,并重新计算crc,再加密生成转发数据。

python程序:

import pyDes
from pyDes import des, CBC, PAD_PKCS5, ECB
import binascii
import datetime
from time import time
from binascii import unhexlify
from crcmod import mkCrcFun


# CRC16/CCITT
def crc16_ccitt(s):
    crc16 = mkCrcFun(0x11021, rev=True, initCrc=0x0000, xorOut=0x0000)
    return get_crc_value(s, crc16)


# CRC16/CCITT-FALSE
def crc16_ccitt_false(s):
    crc16 = mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
    return get_crc_value(s, crc16)


# CRC16/MODBUS
def crc16_modbus(s):
    crc16 = mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
    return get_crc_value(s, crc16)


# CRC16/XMODEM
def crc16_xmodem(s):
    crc16 = mkCrcFun(0x11021, rev=False, initCrc=0x0000, xorOut=0x0000)
    return get_crc_value(s, crc16)


# common func
def get_crc_value(s, crc16):
    data = s.replace(' ', '')
    crc_out = hex(crc16(unhexlify(data))).upper()
    str_list = list(crc_out)
    if len(str_list) == 5:
        str_list.insert(2, '0')  # 位数不足补0
    crc_data = ''.join(str_list[2:])
    # return crc_data[:2] + ' ' + crc_data[2:]
    return crc_data[:2] + crc_data[2:]


def bytesToHexString(data):
    temp = []
    for i in data:
        temp.append('0x%02X' % i)
    return temp


"""
    DES-ECB 加密
    :param s: 原始字符串,密钥
    :return: 加密后字符串,16进制
    """


def des_encrypt(s, key):
    secret_key = key
    iv = secret_key
    k = des(secret_key, pyDes.ECB, IV=iv, padmode=pyDes.PAD_PKCS5)
    en = k.encrypt(s)
    return binascii.b2a_hex(en)


"""
    DES-ECB 解密
    :param s: 原始字符串,密钥
    :return: 解密后字符串,16进制
    """


def des_decrypt(s, key):
    secret_key = key
    iv = secret_key
    k = des(secret_key, pyDes.ECB, IV=iv, padmode=pyDes.PAD_PKCS5)
    en = k.decrypt(s)
    return binascii.b2a_hex(en)


if __name__ == '__main__':
    key = '1111111111111111'
    input_data = '0101e1618051991f4520329c8dec711dd986f7ebf5dcdf7aeec6'
    print("输入报文:", input_data)
    fix_mingwen = input_data[:4]
    print("输入数据的明文部分是", fix_mingwen)
    input_data_miwen = input_data[4:]
    print("输入数据的密文部分是:", input_data_miwen)
    data_body = repr(des_decrypt(bytes.fromhex(input_data_miwen), bytes.fromhex(key)))[2:-1]
    print("解密后的明文:", data_body)

    # 计算此刻的时间戳
    timestamp = hex(int(time())).strip("0x")
    print("此时的时间戳:", timestamp)

    # 计算明文
    data_body = repr(data_body)[1:29] + timestamp
    #crc16 计算有多种模式,这里用crc16_ccitt_false
    crc16_result = crc16_ccitt_false(data_body)
    data_body = data_body + crc16_result
    print("更新的时间戳的明文:", data_body)

    data_body_secrect = des_encrypt(bytes.fromhex(data_body), bytes.fromhex(key))
    data_body_secrect = repr(data_body_secrect)[2:-1]
    print("加密后的密文: ", data_body_secrect)
    data_body_secrect_all = fix_mingwen + data_body_secrect
    print("输出加密后的完整报文:", data_body_secrect_all)

    data_body_length = len(data_body_secrect_all) // 2
    dataList = []
    for i in range(0, data_body_length):
        dataList.append(data_body_secrect_all[2 * i] + data_body_secrect_all[2 * i + 1])  # 每个字节由相邻两个16机制字符组成
    data_body_kongge = " ".join(dataList)
    print("含有空格的报文表示:", data_body_kongge)

自测结果:

输入报文: 0101e1618051991f4520329c8dec711dd986f7ebf5dcdf7aeec6
输入数据的明文部分是 0101
输入数据的密文部分是: e1618051991f4520329c8dec711dd986f7ebf5dcdf7aeec6
解密后的明文: 7072656668313233343536373839644335d2ff0b
此时的时间戳: 64433e0f
更新的时间戳的明文: 707265666831323334353637383964433e0f3921
加密后的密文:  e1618051991f4520329c8dec711dd986d35c06166403b220
输出加密后的完整报文: 0101e1618051991f4520329c8dec711dd986d35c06166403b220
含有空格的报文表示: 01 01 e1 61 80 51 99 1f 45 20 32 9c 8d ec 71 1d d9 86 d3 5c 06 16 64 03 b2 20

Process finished with exit code 0

4. 最后

        DES由于密钥过短,并不认为是安全的密码学算法。一般推荐更新为3DES算法。

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值