DES 加密算法:核心组件、加解密流程与安全特性

DES对称加密算法

一、DES算法原理

算法流程:

  1. 初始置换(IP置换):将输入的64位明文块进行置换和重新排列,生成新的64位数据块。

  2. 加密轮次:DES加密算法共有16个轮次,每个轮次都包括四个步骤:

    1. 将64位数据块分为左右两个32位块。

    2. 右侧32位块作为输入,经过扩展、异或、置换等操作生成一个48位的数据块。这个48位的数据块被称为"轮密钥",它是根据加密算法的主密钥生成的子密钥。

    3. 将左侧32位块和轮密钥进行异或运算,结果作为新的右侧32位块。

    4. 将右侧32位块与原来的左侧32位块进行连接,生成一个新的64位数据块,作为下一轮的输入。

  3. 末置换(FP置换):在最后一个轮次完成后,将经过加密的数据块进行置换和重新排列,得到加密后的64位密文。

算法原理:

  • PC1(密钥置换选择 1) :将 64 位原始密钥去除 8 位校验位,得到 56 位有效密钥,并调整位顺序。

  • PC2(密钥置换选择 2) :将 56 位密钥进一步置换为 48 位,生成每轮的子密钥。

  • IP(初始置换) :对 64 位明文分组进行初始位重排,打破明文原始位顺序。

  • IP_INV(逆初始置换) :与 IP 互为逆作,用于加密最后一步,还原位顺序。

  • E(扩展置换) :将 32 位数据扩展为 48 位,使数据长度与子密钥长度匹配

  • P(P 盒置换) :对 S 盒输出的 32 位数据进行位重排

  • S_BOXES(S 盒) :8 个 4×16 的非线性替代盒,将 6 位输入转换为 4 位输出

对称性数学验证(以 第 2 轮为例)

以 2 轮 Feistel 迭代为例,可直观验证解密的正确性:

  • 加密过程:​(加密输出​)。

  • 解密过程(输入​,子密钥顺序​):第 1 轮解密(用​):​,​(异或抵消轮函数)。第 2 轮解密(用​):​,​(最终还原​)。

通过数学推导可见,反向使用子密钥可完全还原原始数据,证明了 DES 加解密的对称性。

二、DES 算法的弱密钥与安全性

  1. 弱密钥(Weak Keys)

DES 存在 4 个弱密钥,其特点是 "加密与解密等价"(),且 "加密两次还原明文"(),核心原因是弱密钥生成的 16 轮子密钥完全相同。4 个弱密钥(64 位,十六进制):

  • 0000000000000000

  • FFFFFFFFFFFFFFFF

  • 00000000FFFFFFFFFFFFFFFF

  • FFFFFFFFFFFFFFFF00000000

  1. 半弱密钥(Semi-weak Keys)

半弱密钥成对存在(共 6 对),特点是 "用 K1 加密后再用 K2 加密,还原明文"(),核心原因是两对密钥生成的子密钥互为补集。经典半弱密钥对(十六进制):

  • 0101010101010101​ 与 ​FEFEFEFEFEFEFEFE

  • 1F1F1F1F0E0E0E0E​ 与 ​E0E0E0E0F1F1F1F1

  • 01FE01FE01FE01FE​ 与 ​FE01FE01FE01FE01

  • 1FE01FE00EF10EF1​ 与 ​​E01FE01FF10EF10E

  • 01E001E001F101F1​ 与 ​E001E001F101F101

  • 1FFE1FFE0EFE0EFE​ 与 ​FE1FFE1FFE0EFE0E

三、DES算法代码实现

复制代码
"""
请使用编程语言实现对称加密算法DES(语言不限)
要求:
论述DES算法的原理及实现过程
请给出DES算法弱密钥,并通过程序验证弱密钥的危害
编程语言不限
"""
import sys
from typing import List, Tuple

# DES常量定义
# 密钥置换选择1矩阵
PC1 = [
    57, 49, 41, 33, 25, 17, 9,
    1, 58, 50, 42, 34, 26, 18,
    10, 2, 59, 51, 43, 35, 27,
    19, 11, 3, 60, 52, 44, 36,
    63, 55, 47, 39, 31, 23, 15,
    7, 62, 54, 46, 38, 30, 22,
    14, 6, 61, 53, 45, 37, 29,
    21, 13, 5, 28, 20, 12, 4
]
# 密钥置换选择2矩阵
PC2 = [
    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
]
# 加密扩展置换矩阵
E = [
    32, 1, 2, 3, 4, 5, 4, 5,
    6, 7, 8, 9, 8, 9, 10, 11,
    12, 13, 12, 13, 14, 15, 16, 17,
    16, 17, 18, 19, 20, 21, 20, 21,
    22, 23, 24, 25, 24, 25, 26, 27,
    28, 29, 28, 29, 30, 31, 32, 1
]
# P盒置换矩阵
P = [
    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
]
# S盒置换矩阵
S_BOXES = [
    # S1
    [
        [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]
    ],
    # S2
    [
        [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]
    ],
    # S3
    [
        [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]
    ],
    # S4
    [
        [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]
    ],
    # S5
    [
        [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]
    ],
    # S6
    [
        [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]
    ],
    # S7
    [
        [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]
    ],
    # S8
    [
        [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]
    ]
]
# 初始置换矩阵
IP = [
    58, 50, 42, 34, 26, 18, 10, 2,
    60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6,
    64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9, 1,
    59, 51, 43, 35, 27, 19, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5,
    63, 55, 47, 39, 31, 23, 15, 7
]
# 初始置换逆矩阵
IP_INV = [
    40, 8, 48, 16, 56, 24, 64, 32,
    39, 7, 47, 15, 55, 23, 63, 31,
    38, 6, 46, 14, 54, 22, 62, 30,
    37, 5, 45, 13, 53, 21, 61, 29,
    36, 4, 44, 12, 52, 20, 60, 28,
    35, 3, 43, 11, 51, 19, 59, 27,
    34, 2, 42, 10, 50, 18, 58, 26,
    33, 1, 41, 9, 49, 17, 57, 25
]

# 循环左移位数
SHIFT_SCHEDULE = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

# 根据置换表对数据块进行置换
def permute(block: int, table: List[int], n: int) -> int:
    """根据置换表对数据块进行置换"""
    result = 0
    for i, pos in enumerate(table):
        bit = (block >> (n - pos)) & 1
        result |= (bit << (len(table) - 1 - i))
    return result


def generate_subkeys(key: int) -> List[int]:
    """从64位密钥生成16个48位子密钥"""
    # 密钥置换1 (PC1),丢弃8个奇偶校验位
    key_56 = permute(key, PC1, 64)

    # 分为C0和D0
    C = (key_56 >> 28) & 0x0FFFFFFF
    D = key_56 & 0x0FFFFFFF

    subkeys = []
    for i in range(16):
        # 循环左移
        shift = SHIFT_SCHEDULE[i]
        C = ((C << shift) | (C >> (28 - shift))) & 0x0FFFFFFF
        D = ((D << shift) | (D >> (28 - shift))) & 0x0FFFFFFF

        # 合并并应用PC2置换
        CD = (C << 28) | D
        subkey = permute(CD, PC2, 56)
        subkeys.append(subkey)

    return subkeys


def feistel(R: int, subkey: int) -> int:
    """Feistel函数"""
    # 扩展置换
    expanded = permute(R, E, 32)

    # 与子密钥异或
    xored = expanded ^ subkey

    # S盒替代
    s_output = 0
    for i in range(8):
        block = (xored >> (42 - i * 6)) & 0x3F
        # row = ((block >> 5) << 1) | (block & 0x01)
        # col = (block >> 1) & 0x0F
        row = ((block & 0x20) >> 4) | (block & 0x01)
        col = (block >> 1) & 0x0F
        val = S_BOXES[i][row][col]
        s_output |= (val << (28 - i * 4))

    # P盒置换
    return permute(s_output, P, 32)


def des_block(block: int, subkeys: List[int], encrypt: bool = True) -> int:
    """加密或解密单个64位数据块"""
    # 初始置换
    block = permute(block, IP, 64)

    # 分为左右两部分
    L = (block >> 32) & 0xFFFFFFFF
    R = block & 0xFFFFFFFF

    # 16轮Feistel网络
    for i in range(16):
        round_key = subkeys[i] if encrypt else subkeys[15 - i]
        new_L = R
        new_R = L ^ feistel(R, round_key)
        L, R = new_L, new_R

    # 合并左右部分
    combined = (R << 32) | L

    # 逆初始置换
    return permute(combined, IP_INV, 64)


def pkcs7_pad(data: bytes, block_size: int = 8) -> bytes:
    """PKCS#7填充"""
    pad_len = block_size - (len(data) % block_size)
    return data + bytes([pad_len] * pad_len)


def pkcs7_unpad(data: bytes) -> bytes:
    """去除PKCS#7填充"""
    pad_len = data[-1]
    if pad_len < 1 or pad_len > 8:
        raise ValueError("Invalid padding")
    for b in data[-pad_len:]:
        if b != pad_len:
            raise ValueError("Invalid padding")
    return data[:-pad_len]

# 将8字节转换为64位整数
def bytes_to_block(b: bytes) -> int:
    """将8字节转换为64位整数"""
    return int.from_bytes(b, byteorder='big')


def block_to_bytes(block: int) -> bytes:
    """将64位整数转换为8字节"""
    return block.to_bytes(8, byteorder='big')


def des_encrypt(key: bytes, plaintext: bytes) -> bytes:
    """DES加密函数"""
    if len(key) != 8:
        raise ValueError("Key must be 8 bytes (64 bits)")

    key_int = bytes_to_block(key)
    subkeys = generate_subkeys(key_int)

    # 填充明文
    padded = pkcs7_pad(plaintext)

    ciphertext = []
    for i in range(0, len(padded), 8):
        block = bytes_to_block(padded[i:i + 8])
        encrypted = des_block(block, subkeys, encrypt=True)
        ciphertext.append(block_to_bytes(encrypted))

    return b''.join(ciphertext)


def des_decrypt(key: bytes, ciphertext: bytes) -> bytes:
    """DES解密函数"""
    if len(key) != 8:
        raise ValueError("Key must be 8 bytes (64 bits)")
    if len(ciphertext) % 8 != 0:
        raise ValueError("Ciphertext length must be multiple of 8")

    key_int = bytes_to_block(key)
    subkeys = generate_subkeys(key_int)

    plaintext = []
    for i in range(0, len(ciphertext), 8):
        block = bytes_to_block(ciphertext[i:i + 8])
        decrypted = des_block(block, subkeys, encrypt=False)
        plaintext.append(block_to_bytes(decrypted))

    # 去除填充
    return pkcs7_unpad(b''.join(plaintext))


def test_des():
    """测试DES加密解密功能"""
    key = b'22922922'
    plaintext = b'This is a test message for DES encryption.'

    ciphertext = des_encrypt(key, plaintext)
    decrypted = des_decrypt(key, ciphertext)

    print("明文:", plaintext)
    print("密钥:", key)
    print("密文:", ciphertext.hex())
    print("解密:", decrypted)

    assert decrypted == plaintext, "Encryption/decryption failed"

def test_weak_keys():
    """测试DES弱密钥和半弱密钥"""
    # 弱密钥(Weak Keys)
    weak_keys = [
        b'\x01\x01\x01\x01\x01\x01\x01\x01',  
        b'\xFE\xFE\xFE\xFE\xFE\xFE\xFE\xFE',  
        b'\xE0\xE0\xE0\xE0\xF1\xF1\xF1\xF1', 
        b'\x1F\x1F\x1F\x1F\x0E\x0E\x0E\x0E'  
    ]

    # 半弱密钥对(Semi-weak Key Pairs)
    semiweak_pairs = [
        (b'\x01\xFE\x01\xFE\x01\xFE\x01\xFE', b'\xFE\x01\xFE\x01\xFE\x01\xFE\x01'),
        (b'\x1F\xE0\x1F\xE0\x0E\xF1\x0E\xF1', b'\xE0\x1F\xE0\x1F\xF1\x0E\xF1\x0E'),
        (b'\x01\xE0\x01\xE0\x01\xF1\x01\xF1', b'\xE0\x01\xE0\x01\xF1\x01\xF1\x01'),
        (b'\x1F\xFE\x1F\xFE\x0E\xFE\x0E\xFE', b'\xFE\x1F\xFE\x1F\xFE\x0E\xFE\x0E'),
        (b'\x01\x1F\x01\x1F\x01\x0E\x01\x0E', b'\x1F\x01\x1F\x01\x0E\x01\x0E\x01'),
        (b'\xE0\xFE\xE0\xFE\xF1\xFE\xF1\xFE', b'\xFE\xE0\xFE\xE0\xFE\xF1\xFE\xF1')
    ]

    # 使用正好8字节的明文
    plaintext_block = b'12345678'
    print(f"\n弱密钥测试明文块: {plaintext_block.decode()}")

    # ==== 测试弱密钥 ====
    print("===== 弱密钥测试 =====")
    for i, key in enumerate(weak_keys):
        key_int = bytes_to_block(key)
        subkeys = generate_subkeys(key_int)
        block = bytes_to_block(plaintext_block)

        encrypted = des_block(block, subkeys, encrypt=True)
        double_encrypted = des_block(encrypted, subkeys, encrypt=True)
        double_encrypted_bytes = block_to_bytes(double_encrypted)

        print(f"弱密钥 #{i+1}: {key.hex()}")
        if double_encrypted_bytes == plaintext_block:
            print("✅ 弱密钥特性成立: 加密两次等于明文")
        else:
            print("❌ 弱密钥特性不成立")

        # 验证解密
        decrypted = des_block(encrypted, subkeys, encrypt=False)
        if block_to_bytes(decrypted) == plaintext_block:
            print("✅ 解密正确")
        else:
            print("❌ 解密失败")

    print("\n===== 半弱密钥测试 =====")
    for i, (key1, key2) in enumerate(semiweak_pairs):
        key1_int = bytes_to_block(key1)
        key2_int = bytes_to_block(key2)
        subkeys1 = generate_subkeys(key1_int)
        subkeys2 = generate_subkeys(key2_int)
        block = bytes_to_block(plaintext_block)

        # 半弱密钥特性测试:E_{K2}(E_{K1}(P)) = P
        encrypted1 = des_block(block, subkeys1, encrypt=True)  # K1加密
        encrypted2 = des_block(encrypted1, subkeys2, encrypt=True)  # K2加密

        print(f"半弱密钥对 #{i + 1}:\n  K1: {key1.hex()}\n  K2: {key2.hex()}")

        if block_to_bytes(encrypted2) == block_to_bytes(block):
            print("✅ 半弱密钥特性成立: E_{K2}(E_{K1}(P)) = P")
        else:
            print("❌ 半弱密钥特性不成立: E_{K2}(E_{K1}(P)) != P")


if __name__ == "__main__":
    test_des()
    test_weak_keys()

相关推荐
前端小刘哥3 小时前
新版视频直播点播EasyDSS平台,让跨团队沟通高效又顺畅
算法
明月(Alioo)3 小时前
机器学习入门,无监督学习之K-Means聚类算法完全指南:面向Java开发者的Python实现详解
python·算法·机器学习
叶梅树4 小时前
从零构建A股量化交易工具:基于Qlib的全栈系统指南
前端·后端·算法
lingran__4 小时前
算法沉淀第三天(统计二进制中1的个数 两个整数二进制位不同个数)
c++·算法
MicroTech20254 小时前
微算法科技MLGO推出隐私感知联合DNN模型部署和分区优化技术,开启协作边缘推理新时代
科技·算法·dnn
小冯记录编程5 小时前
深入解析C++ for循环原理
开发语言·c++·算法
搞科研的小刘选手5 小时前
【通信&网络安全主题】第六届计算机通信与网络安全国际学术会议(CCNS 2025)
大数据·人工智能·网络安全·vr·通信工程·网络技术·计算机工程
chenchihwen6 小时前
深度解析RAG系统中的PDF解析模块:Docling集成与并行处理实践
python·算法·pdf
做科研的周师兄7 小时前
【机器学习入门】7.4 随机森林:一文吃透随机森林——从原理到核心特点
人工智能·学习·算法·随机森林·机器学习·支持向量机·数据挖掘