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

目录

  • 一、算法原理
  • 每一轮的加密过程
  • 1. 初始分组
  • 2. 16轮迭代加密
  • 3. F函数(核心加密步骤)
  • 4. 16轮加密结束
  • 密钥生成过程
  • 二、代码实例
  • 1.Python版
  • 2.C语言版
  • 3.Java版
  • 一、算法原理

    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) 进行左移操作。左移的位数不是固定的,而是根据当前轮次决定的。具体来说,每一轮的左移位数如下:

    4. 第1、2、9、16轮:左移1位
    5. 其他轮:左移2位
    6. 每一轮左移后的值会生成新的 (C_i) 和 (D_i)。

      注意是循环左移

      C_0, D_0 -> 左移 -> C_1, D_1 -> 左移 -> C_2, D_2 -> …… -> C_16, D_16
      
    7. 密钥置换选择 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
      
    8. 生成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加密算法介绍(含例子)

    作者:扬子期

    物联沃分享整理
    物联沃-IOTWORD物联网 » 对称加密算法——DES算法(包含Python、C、Java语言代码实现)

    发表回复