首页 > Python资料 博客日记

对称加密算法——DES算法(包含Python、C、Java语言代码实现)

2024-11-02 16:00:07Python资料围观5

本篇文章分享对称加密算法——DES算法(包含Python、C、Java语言代码实现),对你有帮助的话记得收藏一下,看Python资料网收获更多编程知识

一、算法原理

DES(数据加密标准)算法对明文数据进行16轮的替换和置换操作,每一轮都会生成一个不同的子密钥,并依次对数据块进行操作。

每一轮的加密过程

DES的每一轮都将64位的明文分为两个部分:左半部分(32位)和右半部分(32位)。加密操作实际上只对右半部分进行变换,而左半部分则直接参与异或运算。具体步骤如下:

1. 初始分组
  • 将64位明文经过初始置换(Initial Permutation, IP),重新排列位的顺序,得到新的64位数据,并将其分为左右两部分:
    • 左半部分:L₀(32位)
    • 右半部分:R₀(32位)
2. 16轮迭代加密

每一轮都会使用不同的子密钥 (K_i),并将当前轮的左半部分 (L_i) 和右半部分 (R_i) 进行如下操作:

  • 步骤 1:将前一轮的右半部分 (R_{i-1}) 作为这一轮的新左半部分,即:

    L_i = R_{i-1}

  • 步骤 2:将前一轮的右半部分 (R_{i-1}) 送入 F函数,并与当前轮的子密钥 (K_i) 进行操作。F函数的详细步骤见后续。F函数的输出结果与前一轮的左半部分 (L_{i-1}) 进行异或运算,生成这一轮的新右半部分 (R_i),即:
    R_i = L_{i-1} ​⊕ F(R_{i-1}, K_i)

  • 步骤 3:继续进行下一轮。经过16轮后,左半部分和右半部分合并,形成64位的加密数据。

在每一轮操作中,左右两部分交换一次位置,从而保证密文与明文之间的复杂关系。

3. F函数(核心加密步骤)

F函数是DES算法中的关键步骤,用于生成复杂的加密结果。F函数将32位的右半部分 (R_{i-1}) 和48位的子密钥 (K_i) 结合起来,具体操作如下:

  • 扩展置换(E扩展):
    32位的右半部分 (R_{i-1}) 经过扩展置换操作,变成48位,扩展时根据一定的规则重复某些位。这一步的作用是增加密文的混淆性,并使其与48位的子密钥 (K_i) 进行异或操作。

  • 异或运算
    将扩展后的48位数据与48位的子密钥 (K_i) 进行异或运算,得到48位的新数据。

  • S盒替代
    将48位数据分成8组,每组6位(48位/6),然后使用8个不同的S盒(Substitution box,替代盒)对每组6位进行替代。S盒的作用是将6位的输入转化为4位的输出,从而将48位数据变成32位。每个S盒都有一个特定的查表,用于根据输入的6位值确定输出的4位值。

    S盒是DES中最重要的非线性变换步骤,是加密过程产生混淆的关键。

  • 置换操作(P盒置换)
    对S盒替代后的32位输出进行置换操作,将数据位重新排列,增加混淆性。经过这一置换操作后,得到最终的32位输出结果。

F函数的输出与当前轮的左半部分进行异或运算,完成这一轮的加密。

4. 16轮加密结束

在完成16轮加密后,得到两个部分:左半部分 (L_{16}) 和右半部分 (R_{16})。此时将这两个部分组合在一起,并进行逆初始置换(Inverse Initial Permutation, IP⁻¹),得到最终的64位密文。

密钥生成过程

DES使用的是一个56位的主密钥(尽管输入是64位的,但其中每8位用于校验,只留下56位用于实际加密),然后通过一系列的位移和置换操作,从这个主密钥中生成16个子密钥,每个子密钥长度为48位。

  1. 去掉奇偶校验位
    虽然输入的密钥是64位,但每8位中的第8位是奇偶校验位。因此,首先需要将64位的密钥中的校验位去除,剩下56位用于密钥生成。

  2. 密钥置换选择 1(PC-1)
    对去除校验位后的56位密钥进行第一次置换,称为置换选择1(Permutation Choice 1,PC-1)。PC-1会根据固定规则重新排列这56位密钥,将其分为两部分:左半部分 (C_0) 和右半部分 (D_0),每部分28位。

    初始56位密钥 -> PC-1 -> 28位的 C_0 和 28位的 D_0
    
  3. 左移操作
    在每一轮加密开始时,都会对(C_0) 和 (D_0) 进行左移操作。左移的位数不是固定的,而是根据当前轮次决定的。具体来说,每一轮的左移位数如下:

    • 第1、2、9、16轮:左移1位
    • 其他轮:左移2位

    每一轮左移后的值会生成新的 (C_i) 和 (D_i)。

    注意是循环左移

    C_0, D_0 -> 左移 -> C_1, D_1 -> 左移 -> C_2, D_2 -> …… -> C_16, D_16
    
  4. 密钥置换选择 2(PC-2)
    左移之后,将 (C_i) 和 (D_i) 组合成56位的密钥,然后使用置换选择2(Permutation Choice 2,PC-2)将这56位压缩为48位。这是通过从56位中选择48位进行排列完成的。PC-2的目的是通过重新选择位的位置并减少位数来生成本轮的子密钥 (K_i)(48位)。

    56位的 C_i + D_i -> PC-2 -> 48位的子密钥 K_i
    
  5. 生成16个子密钥
    通过左移和置换选择2的操作,DES一共会生成16个不同的48位子密钥 (K_1, K_2, …, K_{16}),分别用于每一轮的加密运算。

二、代码实例

1.Python版

# 将十六进制字符串转为二进制字符串
def hex_to_bin(hex_str):
    bin_str = bin(int(hex_str, 16))[2:].zfill(len(hex_str) * 4)
    return bin_str


# 将二进制字符串转为十六进制字符串
def bin_to_hex(bin_str):
    hex_str = hex(int(bin_str, 2))[2:].upper().zfill(len(bin_str) // 4)
    return hex_str


# DES初始置换表
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]

# 扩展置换表
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]

# S盒表
S_BOX = [
    # 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]],
]

# P盒置换表
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]

# 置换选择1(PC-1)表
PC_1 = [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(PC-2)表
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]

# 子密钥生成左移位数
SHIFT_SCHEDULE = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]


# 将输入密钥转为64位,并去除校验位得到56位密钥
def key_permutation(key):
    # key = hex_to_bin(key)
    print('密钥的key:', key)
    key = ''.join(key[i - 1] for i in PC_1)
    return key[:28], key[28:]


# 左移操作
def left_shift(key, shifts):
    return key[shifts:] + key[:shifts]


# 根据C和D生成子密钥
def generate_subkeys(C, D):
    subkeys = []
    for shift in SHIFT_SCHEDULE:
        C = left_shift(C, shift)
        D = left_shift(D, shift)
        subkey = C + D
        # 这里也就是在PC_2的列表为下标,看subkey[i]是什么,全部赋值完后,加入到新的subkey中
        subkey = ''.join(subkey[i - 1] for i in PC_2)
        subkeys.append(subkey)
    return subkeys


# 执行初始置换和逆置换
def permute(data, table):
    return ''.join(data[i - 1] for i in table)


# 加密的核心f函数,包括扩展置换E、S盒和P盒
def f_function(R, K):
    # 1. 扩展置换
    R = ''.join(R[i - 1] for i in E)
    # 2. 与子密钥K进行异或   字符格式转换 int(K, 2)
    R = bin(int(R, 2) ^ int(K, 2))[2:].zfill(48)
    # 3. 经过S盒压缩
    result = ''
    for i in range(8):
        block = R[i * 6:(i + 1) * 6]
        row = int(block[0] + block[5], 2)
        col = int(block[1:5], 2)
        result += bin(S_BOX[i][row][col])[2:].zfill(4)
    # 4. 经过P盒置换
    result = ''.join(result[i - 1] for i in P_BOX)
    return result


# DES加密函数
def des_encrypt(plaintext, key):
    # 1. 初始置换
    plaintext = permute(plaintext, IP)
    # 初始置换后的输出
    print('初始置换后的输出:', plaintext)

    # 2. 分成左右两部分
    L, R = plaintext[:32], plaintext[32:]
    print("R的值为:", R)
    # 生成16轮子密钥
    C, D = key_permutation(key)   # 去掉奇偶校验位
    subkeys = generate_subkeys(C, D)   # 使用列表将每一层密钥存储起来

    # 利用enumerate()函数,遍历密钥列表
    for i, subkey in enumerate(subkeys, 1):
        print(f"第{i}轮子密钥: {bin_to_hex(subkey)}")

    # 3. 进行16轮加密
    for i in range(16):
        L_new = R

        # 查看下变换前L的值
        if i == 0:
            print("第1轮的L变换前的值为:", L)

        R_new = bin(int(L, 2) ^ int(f_function(R, subkeys[i]), 2))[2:].zfill(32)

        L, R = L_new, R_new
        if i == 0:
            print("第1轮的R_new的值为:", R_new)
            print(f"第1轮输出: L = {bin_to_hex(L)}, R = {bin_to_hex(R)}")

    # 4. 合并L和R,逆初始置换
    combined = R + L
    ciphertext = permute(combined, IP_INV)
    return bin_to_hex(ciphertext)


# 主函数
if __name__ == "__main__":
    plaintext = "0123456789ABCDEF"
    key = "133457799BBCDFF1"

    # 转为二进制
    plaintext_bin = hex_to_bin(plaintext)
    key_bin = hex_to_bin(key)
    print("明文的二进制:",plaintext_bin)
    print("密钥的二进制:", key_bin)

    # 加密
    ciphertext = des_encrypt(plaintext_bin, key_bin)

    print(f"最终密文: {ciphertext}")

2.C语言版

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BLOCK_SIZE 64

// IP置换表
int 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};

// 逆初始置换表
int 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};

// E扩展置换表
int 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};

// S盒表
int S_BOX[8][4][16] = {
    // 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}}
};


// P置换表
int 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};

// 左移位数表
int SHIFT_SCHEDULE[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

// 置换选择1(PC-1)表
int PC_1[] = {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(PC-2)表
int 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};

// 将十六进制字符串转换为二进制字符串
void hex_to_bin(char *hex_str, char *bin_str) {
    char *p = hex_str;
    while (*p) {
        switch (*p) {
            case '0': strcat(bin_str, "0000"); break;
            case '1': strcat(bin_str, "0001"); break;
            case '2': strcat(bin_str, "0010"); break;
            case '3': strcat(bin_str, "0011"); break;
            case '4': strcat(bin_str, "0100"); break;
            case '5': strcat(bin_str, "0101"); break;
            case '6': strcat(bin_str, "0110"); break;
            case '7': strcat(bin_str, "0111"); break;
            case '8': strcat(bin_str, "1000"); break;
            case '9': strcat(bin_str, "1001"); break;
            case 'A': strcat(bin_str, "1010"); break;
            case 'B': strcat(bin_str, "1011"); break;
            case 'C': strcat(bin_str, "1100"); break;
            case 'D': strcat(bin_str, "1101"); break;
            case 'E': strcat(bin_str, "1110"); break;
            case 'F': strcat(bin_str, "1111"); break;
        }
        p++;
        
//        printf("plaintext_bin:%s, p:%s \n", bin_str, p);
        
    }
}

// 左移操作
void left_shift(char *key, int shifts) {
    char temp[28];
    strncpy(temp, key, shifts);
    memmove(key, key + shifts, 28 - shifts);
    strncpy(key + 28 - shifts, temp, shifts);
}

// 二进制转换成十六进制 
void bin_to_hex(const char *bin_str) {
    int len = strlen(bin_str);
    int hex_index = 0;
    char hex_str[len]; 

    // 每4个二进制位转换为1个十六进制位
    for (int i = 0; i < len; i += 4) {
        int value = 0;

        // 计算当前4位的二进制值
        for (int j = 0; j < 4; j++) {
            if (bin_str[i + j] == '1') {
                value += (1 << (3 - j)); // 根据位置计算值
            }
        }

        // 将计算的值转换为十六进制字符
        if (value < 10) {
            hex_str[hex_index++] = '0' + value; // 数字
        } else {
            hex_str[hex_index++] = 'A' + (value - 10); // 字母
        }
    }

    hex_str[hex_index] = '\0'; // 添加字符串结束符
    printf("加密后的密文(十六进制):%s\n", hex_str);
}

// 生成子密钥
void generate_subkeys(char *key, char subkeys[16][48]) {
    char C[28], D[28];
    char permuted_key[56];

    // 进行PC-1置换
    for (int i = 0; i < 56; i++) {
        permuted_key[i] = key[PC_1[i] - 1];
    }

    // 分割C和D
    strncpy(C, permuted_key, 28);
    strncpy(D, permuted_key + 28, 28);

    // 生成子密钥
    for (int i = 0; i < 16; i++) {
        left_shift(C, SHIFT_SCHEDULE[i]);
        left_shift(D, SHIFT_SCHEDULE[i]);

        // 合并C和D并进行PC-2置换
        char CD[56];
        strncpy(CD, C, 28);
        strncpy(CD + 28, D, 28);
        for (int j = 0; j < 48; j++) {
            subkeys[i][j] = CD[PC_2[j] - 1];
        }
        printf("subkeys[%d]:%s\n", i, subkeys[i]);
        bin_to_hex(subkeys[i]);
    }
}


// 逆初始置换
void inverse_permutation(char *data, char *perm_data) {
    for (int i = 0; i < 64; i++) {
        perm_data[i] = data[IP_INV[i] - 1];
    }
}

// E扩展置换
void expansion(char *data, char *expanded_data) {
    for (int i = 0; i < 48; i++) {
        expanded_data[i] = data[E[i] - 1];
    }
    expanded_data[48] = '\0'; // 添加终止字符
}




void int_to_bin_str(int value, char *bin_str) {
    for (int i = 3; i >= 0; i--) {
        bin_str[i] = (value % 2) + '0'; // 将二进制位转换为字符
        value /= 2;
    }
    bin_str[4] = '\0'; // 确保字符串以 null 结束
}

// S盒替换
void sbox_substitution(char *data, char *sbox_output) {
    sbox_output[0] = '\0'; // 初始化输出字符串

    for (int i = 0; i < 8; i++) {
        int row = 2 * (data[6 * i] - '0') + (data[6 * i + 5] - '0'); // 计算行
        int col = 8 * (data[6 * i + 1] - '0') + 4 * (data[6 * i + 2] - '0') + 
                  2 * (data[6 * i + 3] - '0') + (data[6 * i + 4] - '0'); // 计算列
        int sbox_value = S_BOX[i][row][col]; // 从 S 盒获取值
        
        char sbox_bin[5];
        int_to_bin_str(sbox_value, sbox_bin); // 将 S 盒输出值转换为二进制字符串
        strncat(sbox_output, sbox_bin, 4); // 连接到输出字符串
    }
}

// P置换
void p_permutation(char *data, char *perm_data) {
    for (int i = 0; i < 32; i++) {
        perm_data[i] = data[P_BOX[i] - 1];
    }
    perm_data[32] = '\0'; // 添加终止字符
}

// 轮函数F
void f_function(char *right, char *subkey, char *output) {
    char expanded_right[48] = {0};
    expansion(right, expanded_right); // 扩展E
    printf("expanded_right: %s\n", expanded_right);
    // 与子密钥进行异或操作
    for (int i = 0; i < 48; i++) {
        expanded_right[i] = ((expanded_right[i] - '0') ^ (subkey[i] - '0')) + '0';
    }
    printf("expanded_right异或后的: %s\n", expanded_right);
    // 通过S盒替换
    char sbox_output[32] = {0};
    sbox_substitution(expanded_right, sbox_output);
    printf("expanded_rights盒sbox_output后的: %s\n", sbox_output);
    // 通过P置换
    p_permutation(sbox_output, output);
}

// 初始置换
void initial_permutation(char *data, char *perm_data) {
    memset(perm_data, 0, 64); // 确保初始化为全0
    for (int i = 0; i < 64; i++) {
        perm_data[i] = data[IP[i] - 1];
//        printf("perm_data length: %d\n", strlen(perm_data));
    }
    
    
    // 打印perm_data的长度 
    printf("perm_data length: %d\n", perm_data[64]);
}

// 16轮迭代加密
void des_encrypt(char *plaintext, char subkeys[16][48], char *ciphertext) {
    char permuted_text[64] = {0};
    initial_permutation(plaintext, permuted_text); // 初始置换
	
    char left[33] = {0}, right[33] = {0};
    strncpy(left, permuted_text, 32);
    strncpy(right, permuted_text + 32, 32);


//    printf("permuted_text_length: %d\n", strlen(permuted_text));
    printf("permuted_left: %s\n", left);
    printf("permuted_right: %s\n", right);
	
    char f_result[33] = {0}, temp[33] = {0};
    for (int i = 0; i < 16; i++) {
        strncpy(temp, right, 32);
        f_function(right, subkeys[i], f_result); // 计算F函数
        printf("f_result: %s\n", f_result);
        
        // 左边与F结果进行异或
        for (int j = 0; j < 32; j++) {
            right[j] = ((left[j] - '0') ^ (f_result[j] - '0')) + '0';
        }
        printf("f_result: %s\n", f_result);
        strncpy(left, temp, 32);
    }
    // 合并左右部分
    char combined[64] = {0};
    strncpy(combined, right, 32);
    strncat(combined, left, 32);
    
    // 逆初始置换
    inverse_permutation(combined, ciphertext);
}


// DES加密主函数
void des_main(char *plaintext_hex, char *key_hex, char *ciphertext_hex) {
    char plaintext_bin[65] = {0};
    char key_bin[65] = {0};
    char ciphertext_bin[65] = {0};
    char subkeys[16][48] = {0};
	printf("plaintext_bin进入前:%s\n", plaintext_bin);
	printf("plaintext_hex:%s\n",plaintext_hex);
    hex_to_bin(plaintext_hex, plaintext_bin); // 明文转换为二进制
    printf("plaintext_bin进入后:%s\n", plaintext_bin);
    printf("key_bin进入前:%s\n", key_bin);
    hex_to_bin(key_hex, key_bin);             // 密钥转换为二进制 
    printf("key_bin进入后:%s\n", key_bin);
    printf("key_bin total:%d\n", strlen(key_bin));
    generate_subkeys(key_bin, subkeys); // 生成16轮子密钥
    des_encrypt(plaintext_bin, subkeys, ciphertext_bin); // 执行加密

    printf("加密后的密文(二进制):%s\n", ciphertext_bin);
    bin_to_hex(ciphertext_bin);
}

int main() {
    char plaintext[] = "0123456789ABCDEF";
    char key[] = "133457799BBCDFF1";
    char ciphertext[17] = {0};

    des_main(plaintext, key, ciphertext);
    return 0;
}


3.Java版

package bean;

import java.util.Arrays;

import org.w3c.dom.ls.LSOutput;

public class DES {
    private static final int BLOCK_SIZE = 64;

    // IP 置换表
    private static final int[] 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};

    // 逆初始置换表
    private static final int[] 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};

    // E 扩展置换表
    private static final int[] 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};

    // S 盒表
    private static final int[][][] S_BOX = {
        {{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}},

        {{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}},

        {{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}},

        {{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}},

        {{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}},

        {{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}},

        {{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}},

        {{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}}
    };

    // P 置换表
    private static final int[] 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};

    // PC-1 和 PC-2 置换表
    private static final int[] PC_1 = {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,
                                        27, 19, 11, 3, 26, 18, 10, 2};

    private static final int[] 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};

    private static final int[] SHIFT_SCHEDULE = {1, 1, 2, 2, 2, 2, 2, 2, 
                                                  1, 2, 2, 2, 2, 2, 2, 1};

// 将十六进制字符串转换为二进制字符串
public static String hexToBin(String hexStr) {
        StringBuilder binStr = new StringBuilder();
        for (char ch : hexStr.toCharArray()) {
            switch (ch) {
                case '0': binStr.append("0000"); break;
                case '1': binStr.append("0001"); break;
                case '2': binStr.append("0010"); break;
                case '3': binStr.append("0011"); break;
                case '4': binStr.append("0100"); break;
                case '5': binStr.append("0101"); break;
                case '6': binStr.append("0110"); break;
                case '7': binStr.append("0111"); break;
                case '8': binStr.append("1000"); break;
                case '9': binStr.append("1001"); break;
                case 'A': binStr.append("1010"); break;
                case 'B': binStr.append("1011"); break;
                case 'C': binStr.append("1100"); break;
                case 'D': binStr.append("1101"); break;
                case 'E': binStr.append("1110"); break;
                case 'F': binStr.append("1111"); break;
            }
        }
        return binStr.toString();
    }

    // 左移操作
//    private static String leftShift(String key, int shifts) {
//        String temp = key.substring(0, shifts);
//        key = key.substring(shifts) + temp;
//        return key;
//    }
//左移操作
private static String leftShift(String key, int shifts) {
 // 左移操作
 return key.substring(shifts) + key.substring(0, shifts);
}

    // 二进制转换成十六进制
    public static String binToHex(String binStr) {
        StringBuilder hexStr = new StringBuilder();
        int len = binStr.length();

        for (int i = 0; i < len; i += 4) {
            int value = Integer.parseInt(binStr.substring(i, i + 4), 2);
            if (value < 10) {
                hexStr.append(value);
            } else {
                hexStr.append((char) ('A' + (value - 10)));
            }
        }
        return hexStr.toString();
    }

 // 生成子密钥
    public static String[] generateSubkeys(String key) {
        String[] subkeys = new String[16];
        StringBuilder permutedKey = new StringBuilder(56);

        // 进行PC-1置换
        for (int i = 0; i < 56; i++) {
            permutedKey.append(key.charAt(PC_1[i] - 1));
        }
     // 打印permutedKey的长度
        System.out.printf("permutedKey: %s\n", permutedKey);
        

        // 分割C和D
        String C = permutedKey.substring(0, 28);
        String D = permutedKey.substring(28);
        System.out.printf("permutedKey C: %s\n", C);
        System.out.printf("permutedKey D: %s\n", D);
        // 生成子密钥
        for (int i = 0; i < 16; i++) {
            // 左移
            C = leftShift(C, SHIFT_SCHEDULE[i]);
            D = leftShift(D, SHIFT_SCHEDULE[i]);
            System.out.printf("permutedKey C左移: %s\n", C);
            System.out.printf("permutedKey D左移: %s\n", D);
            // 合并C和D并进行PC-2置换
            StringBuilder CD = new StringBuilder(C).append(D);
            System.out.printf("permutedKey CD: %s\n", CD);
            StringBuilder subkey = new StringBuilder(48);

            // 进行PC-2置换
            for (int j = 0; j < 48; j++) {
                subkey.append(CD.charAt(PC_2[j] - 1));
            }

            subkeys[i] = subkey.toString();
            System.out.printf("subkeys[%d]: %s\n", i, subkeys[i]);
            System.out.printf("第%d次加密后的密钥(十六进制):%s\n", i+1,binToHex(subkeys[i]));
        }
        return subkeys;
    }


    // 逆初始置换
    public static String inversePermutation(String data) {
        StringBuilder permData = new StringBuilder(64);
        for (int i = 0; i < 64; i++) {
            permData.append(data.charAt(IP_INV[i] - 1));
        }
        return permData.toString();
    }

    // E扩展置换
    public static String expansion(String data) {
        StringBuilder expandedData = new StringBuilder(48);
        for (int i = 0; i < 48; i++) {
            expandedData.append(data.charAt(E[i] - 1));
        }
        return expandedData.toString();
    }

    // S盒替换
    public static String sboxSubstitution(String data) {
        StringBuilder sboxOutput = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            int row = 2 * (data.charAt(6 * i) - '0') + (data.charAt(6 * i + 5) - '0');
            int col = 8 * (data.charAt(6 * i + 1) - '0') + 4 * (data.charAt(6 * i + 2) - '0')
                    + 2 * (data.charAt(6 * i + 3) - '0') + (data.charAt(6 * i + 4) - '0');
            int sboxValue = S_BOX[i][row][col];

            String sboxBin = String.format("%4s", Integer.toBinaryString(sboxValue)).replace(' ', '0');
            sboxOutput.append(sboxBin);
        }
        return sboxOutput.toString();
    }

    // P置换
    public static String pPermutation(String data) {
        StringBuilder permData = new StringBuilder(32);
        for (int i = 0; i < 32; i++) {
            permData.append(data.charAt(P_BOX[i] - 1));
        }
        return permData.toString();
    }

    // 轮函数F
    public static String fFunction(String right, String subkey) {
        String expandedRight = expansion(right);
        StringBuilder xorResult = new StringBuilder(48);

        // 与子密钥进行异或操作
        for (int i = 0; i < 48; i++) {
            xorResult.append((char) ((expandedRight.charAt(i) - '0') ^ (subkey.charAt(i) - '0') + '0'));
        }

        // 通过S盒替换
        String sboxOutput = sboxSubstitution(xorResult.toString());

        // 通过P置换
        return pPermutation(sboxOutput);
    }

    // 初始置换
    public static String initialPermutation(String data) {
        StringBuilder permData = new StringBuilder(64);
        for (int i = 0; i < 64; i++) {
            permData.append(data.charAt(IP[i] - 1));
        }
        return permData.toString();
    }

    // 16轮迭代加密
    public static String desEncrypt(String plaintext, String[] subkeys) {
        String permutedText = initialPermutation(plaintext);
        String left = permutedText.substring(0, 32);
        String right = permutedText.substring(32);

        for (int i = 0; i < 16; i++) {
            String temp = right;
            String fResult = fFunction(right, subkeys[i]);
            System.out.printf("fResult右边经过F函数:%s\n", fResult);
            // 左边与F结果进行异或
            StringBuilder newRight = new StringBuilder(32);
            for (int j = 0; j < 32; j++) {
                newRight.append((char) ((left.charAt(j) - '0') ^ (fResult.charAt(j) - '0') + '0'));
            }
            right = newRight.toString();
            left = temp;
            String combine = right + left;
//            System.out.printf("加密后的密文(十六进制):%s\n", binToHex(combine));
            System.out.printf("第%d次加密后的密文(十六进制):%s\n", i+1,binToHex(combine));
        }
        
        // 合并左右部分
        String combined = right + left;
        return inversePermutation(combined);
    }

    // DES加密主函数
    public static void desMain(String plaintextHex, String keyHex) {
        String plaintextBin = hexToBin(plaintextHex); // 明文转换为二进制
        String keyBin = hexToBin(keyHex);             // 密钥转换为二进制
//        System.out.printf("加密后的密文(二进制):%s\n", keyBin);
        String[] subkeys = generateSubkeys(keyBin);   // 生成16轮子密钥
        String ciphertextBin = desEncrypt(plaintextBin, subkeys); // 执行加密

        System.out.printf("加密后的密文(二进制):%s\n", ciphertextBin);
        System.out.printf("加密后的密文(十六进制):%s\n", binToHex(ciphertextBin));
    }

    public static void main(String[] args) {
        String plaintext = "0123456789ABCDEF";
        String key = "133457799BBCDFF1"; // 64位密钥

        desMain(plaintext, key);
    }
}

下面这个链接是结合例子讲解的,讲的不错
链接: DES加密算法介绍(含例子)


版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐