DES(Data Encryption Standard)
DES简介
DES(Data Encryption Standard,数据加密标准) 是一种对称密钥加密算法,由IBM在1970年代为美国国家标准局(NBS,现为NIST)设计,1977年被采纳为联邦信息处理标准(FIPS)。DES曾广泛用于数据的保护和加密,是当时最流行的加密方法之一。
工作原理
DES 是一种 对称加密算法,这意味着同一个密钥用于加密和解密。它采用 块加密 的方式,将数据分成固定大小的块(通常是64位),然后对每个块进行加密操作。
1. 密钥
DES 密钥由 8 个字节(每个字节 8 位)组成,其中每个字节的最后一位是校验位。校验位是这样设置的:
每个字节的前 7 位用于加密(即 56 位有效加密位)。 每个字节的第 8 位(最高位)是奇偶校验位,确保每个字节中有奇数个“1”。
校验位计算:
对于每个 8 位字节,计算其前 7 位中“1”的个数。 如果前 7 位的“1”的个数是偶数,则校验位(第 8 位)设为 1,使得整个字节有奇数个“1”。 如果前 7 位的“1”的个数是奇数,则校验位设为 0,保持奇数个“1”。
2. 初始置换 (Initial Permutation, IP)
加密开始前,明文块首先通过一个初始置换,将数据的位重新排列。这个操作虽然不增加安全性,但被设计成算法的固定部分。
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)
所有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简介
3DES(Triple Data Encryption Standard,三重数据加密标准)是一种对称密钥加密算法,它是在传统 DES(Data Encryption Standard)基础上改进而来的。3DES 的设计目的是增强 DES 的安全性,以应对由于 DES 密钥长度较短(56 位)而带来的安全性不足问题。
3DES的工作原理
3DES 的核心思想是通过多次应用 DES 算法来增加安全性。具体来说,3DES 使用三次 DES 加密过程来加密数据,这也是它名字的由来。3DES 主要有两种加密模式:
1. EDE 模式(加密-解密-加密)
EDE 模式是最常用的 3DES 模式:
- 步骤 1: 使用第一个密钥
K1
对数据进行 DES 加密。 - 步骤 2: 使用第二个密钥
K2
对步骤 1 的输出进行 DES 解密。 - 步骤 3: 使用第三个密钥
K3
对步骤 2 的输出进行 DES 加密,得到最终的密文。
2. EEE 模式(加密-加密-加密)
EEE 模式也可以使用,但较少见:
- 步骤 1: 使用第一个密钥
K1
对数据进行 DES 加密。 - 步骤 2: 使用第二个密钥
K2
对步骤 1 的输出进行 DES 加密。 - 步骤 3: 使用第三个密钥
K3
对步骤 2 的输出进行 DES 加密,得到最终的密文。
3DES的密钥长度
3DES 可以使用两种密钥长度:
- 2 密钥 3DES(2-key 3DES):
K1
和K3
使用相同的密钥,因此有效密钥长度为 112 位(两个 56 位密钥)。 - 3 密钥 3DES(3-key 3DES):
K1
、K2
和K3
都使用不同的密钥,因此有效密钥长度为 168 位(三个 56 位密钥)。
3DES的优缺点
优点:
- 增强的安全性:3DES 通过三次应用 DES 加密算法,大大提高了对暴力破解的抵抗能力,扩展了密钥空间。
- 向后兼容:3DES 继承了 DES 的设计思想,因此可以在需要兼容传统 DES 系统的场合使用。
缺点:
- 速度较慢:由于需要进行三次 DES 运算,3DES 的加密和解密速度比单次 DES 慢了三倍,不适合资源受限的设备。
- 密钥管理复杂:3DES 需要管理 2 或 3 个密钥,密钥管理比 DES 更复杂。
3DES的使用场景
由于其安全性和向后兼容性,3DES 曾在金融服务、支付系统和某些政府应用中得到广泛使用。然而,随着计算能力的不断提升和更安全的算法(如 AES)的出现,3DES 在现代应用中逐渐被淘汰。