DES(Data Encryption Standard)
DES 简介
Section titled “DES 简介”DES(Data Encryption Standard,数据加密标准) 是一种对称密钥加密算法,由 IBM 在 1970 年代为美国国家标准局(NBS,现为 NIST)设计,1977 年被采纳为联邦信息处理标准(FIPS)。DES 的有效密钥长度只有 56 位,现代安全系统不应再使用单 DES 保护数据。
DES 是一种 对称加密算法,这意味着同一个密钥用于加密和解密。它采用 块加密 的方式,将数据分成固定大小的块(通常是 64 位),然后对每个块进行加密操作。
DES 密钥由 8 个字节(每个字节 8 位)组成,其中每个字节的最后一位是校验位。校验位是这样设置的:
每个字节的前 7 位用于加密(即 56 位有效加密位)。每个字节的第 8 位(最高位)是奇偶校验位,确保每个字节中有奇数个“1”。
校验位计算:
对于每个 8 位字节,计算其前 7 位中“1”的个数。如果前 7 位的“1”的个数是偶数,则校验位(第 8 位)设为 1,使得整个字节有奇数个“1”。如果前 7 位的“1”的个数是奇数,则校验位设为 0,保持奇数个“1”。
2. 初始置换 (Initial Permutation, IP)
Section titled “2. 初始置换 (Initial Permutation, IP)”加密开始前,明文块首先通过一个初始置换,将数据的位重新排列。这个操作虽然不增加安全性,但被设计成算法的固定部分。
3. 16 轮的 Feistel 结构
Section titled “3. 16 轮的 Feistel 结构”DES 采用了 Feistel 网络结构,每一轮都对数据块进行复杂的操作:
- 数据分组:将 64 位的数据块分为左右两部分,各 32 位。
- 轮函数 (Round Function, F-Function):每一轮使用的 48 位子密钥和右半部分结合,经过一系列操作生成新的数据块。
- 扩展置换 (Expansion Permutation, E-Box):右半部分由 32 位扩展为 48 位。
- 与子密钥异或:扩展后的数据块与本轮的子密钥进行异或操作。
- S- 盒替换 (Substitution, S-Box):异或后的 48 位数据被分为 8 组,每组 6 位,通过 S- 盒进行非线性替换,将 6 位压缩为 4 位。
- P- 盒置换 (Permutation, P-Box):经过 S- 盒替换后的 32 位数据再经过 P- 盒置换,以增加混淆度。
- 左右交换:将本轮输出的左右部分交换,为下一轮输入做准备。
4. 逆初始置换 (Inverse Initial Permutation, IP-1)
Section titled “4. 逆初始置换 (Inverse Initial Permutation, IP-1)”所有 16 轮完成后,将数据块经过一次逆初始置换,恢复数据的原始位序。
c 语言实现示例
#include <stdio.h>#include <stdlib.h>
#define LB32_MASK 0x00000001#define LB64_MASK 0x0000000000000001#define L64_MASK 0x00000000ffffffff#define H64_MASK 0xffffffff00000000
/* Initial Permutation Table */static char 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};
/* Inverse Initial Permutation Table */static char PI[] = { 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};
/*Expansion table */static char 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};
/* Post S-Box permutation */static char 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};
/* The S-Box tables */static char S[8][64] = {{ /* 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 }};
/* Permuted Choice 1 Table */static char 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};
/* Permuted Choice 2 Table */static char 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};
/* Iteration Shift Array */static char iteration_shift[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
/** * * @param input 加密的明文 * @param key 加密的密码 * @param mode 'd'是解密'e'为加密 * @return */uint64_t des(uint64_t input, uint64_t key, char mode) { int i, j;
// 用于表示行和列的变量,用于S-盒选择 char row, column;
// 28位变量,用于存储密钥的C和D部分 uint32_t C = 0; uint32_t D = 0;
// 32位变量,用于存储L和R部分以及函数结果 uint32_t L = 0; uint32_t R = 0; uint32_t s_output = 0; uint32_t f_function_res = 0; uint32_t temp = 0;
// 48位变量,用于存储子密钥和扩展后的R部分 uint64_t sub_key[16] = {0}; uint64_t s_input = 0;
// 56位变量,用于存储置换选择1和2的结果 uint64_t permuted_choice_1 = 0; uint64_t permuted_choice_2 = 0;
// 64位变量,用于存储初始置换、DES结果和输出前的中间结果 uint64_t init_perm_res = 0; uint64_t des_result = 0; uint64_t pre_output = 0;
// 初始置换(IP置换) for (i = 0; i < 64; i++) { init_perm_res <<= 1; init_perm_res |= (input >> (64-IP[i])) & LB64_MASK; }
// 将初始置换结果拆分为左右两部分 L = (uint32_t) (init_perm_res >> 32) & L64_MASK; R = (uint32_t) init_perm_res & L64_MASK;
// 生成16轮子密钥 for (i = 0; i < 56; i++) { permuted_choice_1 <<= 1; permuted_choice_1 |= (key >> (64-PC1[i])) & LB64_MASK; }
// 将置换选择1的结果分为C和D部分 C = (uint32_t) ((permuted_choice_1 >> 28) & 0x000000000fffffff); D = (uint32_t) (permuted_choice_1 & 0x000000000fffffff);
// 进行16轮左移和生成子密钥 for (i = 0; i < 16; i++) { for (j = 0; j < iteration_shift[i]; j++) { // 左移操作 C = (0x0fffffff & (C << 1)) | (0x00000001 & (C >> 27)); D = (0x0fffffff & (D << 1)) | (0x00000001 & (D >> 27)); }
// 将C和D合并 permuted_choice_2 = 0; permuted_choice_2 = (((uint64_t) C) << 28) | (uint64_t) D;
// 生成子密钥 sub_key[i] = 0; for (j = 0; j < 48; j++) { sub_key[i] <<= 1; sub_key[i] |= (permuted_choice_2 >> (56-PC2[j])) & LB64_MASK; } }
// 16轮加密/解密过程 for (i = 0; i < 16; i++) { // f函数的输入是R部分的扩展结果 s_input = 0; for (j = 0; j < 48; j++) { s_input <<= 1; s_input |= (uint64_t) ((R >> (32-E[j])) & LB32_MASK); }
// 根据模式选择子密钥进行异或操作 if (mode == 'd') { // 解密模式 s_input = s_input ^ sub_key[15-i]; } else { // 加密模式 s_input = s_input ^ sub_key[i]; }
// S-盒替换 for (j = 0; j < 8; j++) { row = (char) ((s_input & (0x0000840000000000 >> (6*j))) >> (42-6*j)); row = (row >> 4) | (row & 0x01);
column = (char) ((s_input & (0x0000780000000000 >> (6*j))) >> (43-6*j));
s_output <<= 4; s_output |= (uint32_t) (S[j][16*row + column] & 0x0f); }
// P置换 f_function_res = 0; for (j = 0; j < 32; j++) { f_function_res <<= 1; f_function_res |= (s_output >> (32 - P[j])) & LB32_MASK; }
// L和R部分交换 temp = R; R = L ^ f_function_res; L = temp; }
// 将L和R部分合并成64位结果 pre_output = (((uint64_t) R) << 32) | (uint64_t) L;
// 逆初始置换(PI置换) for (i = 0; i < 64; i++) { des_result <<= 1; des_result |= (pre_output >> (64-PI[i])) & LB64_MASK; }
// 返回最终加密/解密结果 return des_result;}
int main(int argc, char *argv[]){
char mode = 'e'; uint64_t input = 0x3132333435363738; uint64_t key = 0x3030303030303030;
printf("%016llX\n", des(input, key, mode));
return 0;}3DES 简介
Section titled “3DES 简介”3DES(Triple Data Encryption Standard,三重数据加密标准)是一种对称密钥加密算法,它是在传统 DES(Data Encryption Standard)基础上改进而来的。3DES 的设计目的是增强 DES 的安全性,以应对由于 DES 密钥长度较短(56 位)而带来的安全性不足问题。
3DES 的工作原理
Section titled “3DES 的工作原理”3DES 的核心思想是通过多次应用 DES 算法来增加安全性。具体来说,3DES 使用三次 DES 加密过程来加密数据,这也是它名字的由来。3DES 主要有两种加密模式:
1. EDE 模式(加密 - 解密 - 加密)
Section titled “1. EDE 模式(加密 - 解密 - 加密)”EDE 模式是最常用的 3DES 模式:
- 步骤 1: 使用第一个密钥
K1对数据进行 DES 加密。 - 步骤 2: 使用第二个密钥
K2对步骤 1 的输出进行 DES 解密。 - 步骤 3: 使用第三个密钥
K3对步骤 2 的输出进行 DES 加密,得到最终的密文。
2. EEE 模式(加密 - 加密 - 加密)
Section titled “2. EEE 模式(加密 - 加密 - 加密)”EEE 模式也可以使用,但较少见:
- 步骤 1: 使用第一个密钥
K1对数据进行 DES 加密。 - 步骤 2: 使用第二个密钥
K2对步骤 1 的输出进行 DES 加密。 - 步骤 3: 使用第三个密钥
K3对步骤 2 的输出进行 DES 加密,得到最终的密文。
3DES 的密钥长度
Section titled “3DES 的密钥长度”3DES 可以使用两种密钥长度:
- 2 密钥 3DES(2-key 3DES):
K1和K3使用相同的密钥,因此有效密钥长度为 112 位(两个 56 位密钥)。 - 3 密钥 3DES(3-key 3DES):
K1、K2和K3都使用不同的密钥,因此有效密钥长度为 168 位(三个 56 位密钥)。
3DES 的优缺点
Section titled “3DES 的优缺点”- 历史安全增强:3DES 通过多次应用 DES 扩展了有效密钥空间,曾作为过渡方案使用;按照 NIST SP 800-131A Rev. 2,TDEA/3DES 加密已进入弃用/不允许继续生成保护的阶段,现代系统应优先使用 AES。
- 向后兼容:3DES 继承了 DES 的设计思想,因此可以在需要兼容传统 DES 系统的场合使用。
- 速度较慢:由于需要进行三次 DES 运算,3DES 的加密和解密速度比单次 DES 慢了三倍,不适合资源受限的设备。
- 密钥管理复杂:3DES 需要管理 2 或 3 个密钥,密钥管理比 DES 更复杂。
3DES 的使用场景
Section titled “3DES 的使用场景”由于其向后兼容性,3DES 曾在金融服务、支付系统和某些政府应用中得到广泛使用。随着计算能力提升和 AES 普及,DES/3DES 都不应作为新系统的首选加密算法。
- NIST SP 800-131A Rev. 2(访问日期:2026-05-31)
- NIST FIPS 197: Advanced Encryption Standard (AES)(访问日期:2026-05-31)