1 はじめに
DES アルゴリズムは、1971 年に IBM によって提案された共通ブロック暗号化アルゴリズムです。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 試験要件の「応用暗号」コンテンツは、記憶と興味深い講義に役立ちます_Xiaoxiangzai のブログ-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 ボックス置換、左右チェックの 4 つの部分が含まれます。
2.4 逆順列
2.5 復号化
復号化プロセスは暗号化プロセスと同じですが、順序が逆になります。
2.6 データの入力
平文の長さがパケット長の整数倍ではない場合、パケット長を構成するために最後のパケットに何らかのデータを埋める必要があります。
NoPadding
API またはアルゴリズム自体はデータを処理せず、暗号化されたデータは暗号化当事者によって合意されたアルゴリズムで埋められます。たとえば、文字列データを暗号化および復号化する場合は、\0 またはスペースを追加してトリミングします。
PKCS5Padding
暗号化の前: データのバイト長は 8 で、残りは m です。m>0 の場合、8-m バイトで構成され、バイト値は 8-m です。セクションでは、バイト値は送信するバイト数です。 0の場合、
復号化後に8バイトが追加されます。最後のバイトを取得し、値はmで、データの末尾からmバイトを削除します。残りのデータは暗号化前の元のテキストです。
暗号化文字列が AAA の場合、パディングは AAA55555、暗号化文字列が BBBBBB の場合、パディングは BBBBBB22、暗号化文字列が CCCCCCCC の場合、パディングは CCCCCCCC88888888 です。
PKCS7Padding
PKCS7Padding の充填方法は PKCS5Padding と同じです。暗号化ブロックのバイト数のみが異なります。PKCS5Padding は、暗号化ブロックが 8 バイトであり、PKCS7Padding の暗号化ブロックは 1 ~ 255 であることが明確に定義されています。
2.7 暗号化モード
電子コードブック (ECB) モード
汎用: 秘密キーや PIN 値などの少量のデータを暗号化します。
暗号ブロックチェーン (Cipher Block Chaining、CBC) モード
汎用: 大規模データの暗号化
暗号フィードバック (CFB) モード
汎用: 小さいデータの暗号化、各ビットを個別に暗号化
出力フィードバック (OFB) モード
特徴:OFBよりも展開エラーが起こりにくい
カウント (CounTeR、CTR) モード。
特徴:IVカウンター、パラレル
参考
このブログは DES 暗号化の原理を分かりやすく解説しており、一読の価値があります。
DES 暗号化アルゴリズムの原理とコードの実装_des 暗号化アルゴリズム code_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. すべて 16 進数で表現された「平文プレフィックス」+「暗号文」を取得します。暗号文は「固定長固定ビット + タイムスタンプ + 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 アルゴリズムに更新することをお勧めします。