DES算法原理
DES算法原理
DES加密
DES算法采用的是64位分组长度和56位的密钥长度,其算法原理是基于Feistel进行的改进。
加密流程
- 明文进行初始IP置换。
- 明文分成左右各32位子明文。
- 左右子明文经过16轮加密(F函数、16轮子密钥)。
- 左右子密文交换位置合成64位加密后的密文。
- 密文经过IP逆置换得到最后的密文。
16轮子密钥
F函数
加密演示示例
- 明文 密钥
明文:01100011 01101111 01101101 01110000 01110101 01110100 01100101 01110010
密钥:00010011 00110100 01010111 01111001 10011011 10111100 11011111 11110001
- 明文IP置换
IP置换后的明文:11111111 10111000 01110110 01010111 00000000 11111111 00000110 10000011
- 密钥处理
PC1置换后的密钥:11110000 11001100 10101010 11110101 01010110 01100111 10001111
密钥对半拆分为初始C0 D0
C0:1111000 0110011 0010101 0101111
D0:0101010 1011001 1001111 0001111
C0 D0 循环左移生成 C1 D1
C1:1110000 1100110 0101010 1011111
D1:1010101 0110011 0011110 0011110
C1 D1 经过PC2置换生成K1
K1:00011011 00000010 11101111 11111100 01110000 01110010
同上处理,C1 D1再次左移生成C2 D2,然后经过PC2置换生成K2
C2:1100001 1001100 1010101 0111111
D2:0101010 1100110 0111100 0111101
K2:01111001 10101110 11011001 11011011 11001001 11100101
C3:
D3:
K3:
C4:
D4:
K4:
C5:
D5:
K5:
C6:
D6:
K6:
C7:
D7:
K7:
C8:
D8:
K8:
C9:
D9:
K9:
C10:
D10:
K10:
C11:
D11:
K11:
C12:
D12:
K12:
C13:
D13:
K13:
C14:
D14:
K14:
C15:
D15:
K15:
C16:1111000 0110011 0010101 0101111
D16:0101010 1011001 1001111 0001111
K16:11001011 00111101 10001011 00001110 00010111 11110101
- F函数处理
IP置换后的明文拆分成初始的L0 R0
L0:11111111 10111000 01110110 01010111
R0:00000000 11111111 00000110 10000011
R0经过E盒扩展得到E1
E1:10000000 00010111 11111110 10000000 11010100 00000110
E1和K1经过异或得到EK1
EK1:10011011 00010101 00010001 01111100 10100100 01110100
EK1经过S盒压缩得到S1
S1:10001011 11000100 01100010 11101010
S1经过P盒置换得到P1
P1:01001000 10111111 01010101 10000001
P1和L0经过异或得到R1
R1:
78/*
DES解密
解密流程和加密流程基本一致,仅在16轮加解密过程中使用密钥的顺序有区别:
- 加密:使用
K1 ---> K16子密钥。 - 解密:使用
K16 ---> K1子密钥。
代码实现-C语言
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*
* 使用指南:
* 1. 编译命令示例:
* gcc des_code.c -o des_code -w -lm
* 2. 运行程序:
* ./des_code
*/
// 初始IP置换表
static const int ip_table[64] = {
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逆置换表
static const int ipre_table[64] = {
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扩展运算表
static const int e_table[48] = {
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盒置换表
static const int p_table[32] = {
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盒置换表
static const int s_table[8][4][16] = {
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 };
// PC1置换表
static const int pc1_table[56] = {
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 };
// PC2置换表
static const int pc2_table[48] = {
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 };
// 左移位数表
static const int ls_table[16] = {
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
// 单字节字符转十六进制
/*
* src:入参 单字节字符串
* hex:出参 十六进制字符串
*/
void single_byte_character_to_hex(char *src, char* hex)
{
int offset = 0;
for (int i = 0; i < strlen(src); i++) {
sprintf(hex + offset, "%x", src[i]);
offset += 2;
}
}
// 2进制转10进制
int bin2dec(char *bin)
{
int res = 0;
int len = strlen(bin);
char temp[2] = {'0', '1'};
for (size_t i = 0; i < len; i++) {
if (bin[len - i - 1] == temp[1]) {
res += pow(2, i); // 计算2的i次方并累加
}
}
return res;
}
// 十进制转二进制
int dec2bin(int n)
{
int sum = 0;
int y, x = 1; // y表示余数,x为叠加的系数
while (n != 0) {
y = n % 2;
sum += x * y;
x *= 10;
n /= 2;
}
return sum;
}
// 十六进制转二进制
void hex2bin(char *hex, char *bin)
{
int len = strlen(hex);
char buff[65] = { 0 };
char binbuff[65] = { 0 };
for (int i = 0; i < len; i++) {
switch (hex[i]) {
case '0':
strcpy(buff, "0000");
strncat(binbuff, buff, 4);
break;
case '1':
strcpy(buff, "0001");
strncat(binbuff, buff, 4);
break;
case '2':
strcpy(buff, "0010");
strncat(binbuff, buff, 4);
break;
case '3':
strcpy(buff, "0011");
strncat(binbuff, buff, 4);
break;
case '4':
strcpy(buff, "0100");
strncat(binbuff, buff, 4);
break;
case '5':
strcpy(buff, "0101");
strncat(binbuff, buff, 4);
break;
case '6':
strcpy(buff, "0110");
strncat(binbuff, buff, 4);
break;
case '7':
strcpy(buff, "0111");
strncat(binbuff, buff, 4);
break;
case '8':
strcpy(buff, "1000");
strncat(binbuff, buff, 4);
break;
case '9':
strcpy(buff, "1001");
strncat(binbuff, buff, 4);
break;
case 'a':
case 'A':
strcpy(buff, "1010");
strncat(binbuff, buff, 4);
break;
case 'b':
case 'B':
strcpy(buff, "1011");
strncat(binbuff, buff, 4);
break;
case 'c':
case 'C':
strcpy(buff, "1100");
strncat(binbuff, buff, 4);
break;
case 'd':
case 'D':
strcpy(buff, "1101");
strncat(binbuff, buff, 4);
break;
case 'e':
case 'E':
strcpy(buff, "1110");
strncat(binbuff, buff, 4);
break;
case 'f':
case 'F':
strcpy(buff, "1111");
strncat(binbuff, buff, 4);
break;
default:
printf("err hex\n");
break;
}
}
strcpy(bin, binbuff);
}
// 二进制转十六进制
void bin2hex(char *bin, char *hex)
{
int len = strlen(bin) / 4;
char buf[5] = { 0 };
for (size_t i = 0; i < len; i++) {
for (size_t j = 0; j < 4; j++) {
buf[j] = bin[i * 4 + j];
}
int dec = bin2dec(buf);
switch (dec) {
case 0:
hex[i] = '0';
break;
case 1:
hex[i] = '1';
break;
case 2:
hex[i] = '2';
break;
case 3:
hex[i] = '3';
break;
case 4:
hex[i] = '4';
break;
case 5:
hex[i] = '5';
break;
case 6:
hex[i] = '6';
break;
case 7:
hex[i] = '7';
break;
case 8:
hex[i] = '8';
break;
case 9:
hex[i] = '9';
break;
case 10:
hex[i] = 'A';
break;
case 11:
hex[i] = 'B';
break;
case 12:
hex[i] = 'C';
break;
case 13:
hex[i] = 'D';
break;
case 14:
hex[i] = 'E';
break;
case 15:
hex[i] = 'F';
break;
default:
break;
}
}
}
// 初始IP置换
void init_switch(char *m)
{
char temp[65] = { 0 };
strcpy(temp, m);
for (int i = 0; i < 64; i++) {
m[i] = temp[ip_table[i] - 1];
}
}
// IP逆置换
void re_ipswitch(char *m)
{
char temp[65] = { 0 };
strcpy(temp, m);
for (int i = 0; i < 64; i++) {
m[i] = temp[ipre_table[i] - 1];
}
}
// E扩展运算
void extend(char *r, char *e)
{
for (int i = 0; i < 48; i++) {
e[i] = r[e_table[i] - 1];
}
}
// S盒置换
void s_switch(char *str, char *end)
{
char s[7] = { 0 };
char hang[3] = { 0 };
int h = 0;
char lie[5] = { 0 };
int l = 0;
int afters[8] = { 0 };
for (size_t i = 0; i < 8; i++) {
for (size_t j = 0; j < 6; j++) {
s[j] = str[6 * i + j];
}
hang[0] = s[0];
hang[1] = s[5];
for (size_t k = 0; k < 4; k++) {
lie[k] = s[1 + k];
}
// 二进制转十进制
h = bin2dec(hang);
l = bin2dec(lie);
// 完成S盒转换
afters[i] = s_table[i][h][l];
}
char buf[5] = { 0 };
for (size_t i = 0; i < 8; i++) {
// 将S盒变换后的数字转成二进制,并补位成四位
snprintf(buf, sizeof(buf), "%04d", dec2bin(afters[i]));
int lenofbuf = strlen(buf);
switch (lenofbuf) {
case 4:
break;
// 进行补位
case 3:
buf[3] = buf[2];
buf[2] = buf[1];
buf[1] = buf[0];
buf[0] = '0';
break;
case 2:
buf[2] = buf[0];
buf[3] = buf[1];
buf[0] = '0';
buf[1] = '0';
break;
case 1:
buf[3] = buf[0];
buf[0] = '0';
buf[1] = '0';
buf[2] = '0';
break;
default:
break;
}
for (size_t j = 0; j < 4; j++) {
end[4 * i + j] = buf[j];
}
}
}
// P盒置换
void p_switch(char *start, char *end)
{
for (size_t i = 0; i < 32; i++) {
end[i] = start[p_table[i] - 1];
}
}
// 异或运算
// 参数分别为异或的两个数,返回的结果和异或的位数
void xor(char *a, char *b, char *res, int len)
{
if (a == NULL) { // 初始向量为空时,直接返回b
strcpy(res, b);
}
char ret[64] = { 0 };
for (size_t i = 0; i < len; i++) {
if (a[i] == b[i]) {
ret[i] = '0';
} else {
ret[i] = '1';
}
}
strcpy(res, ret);
}
// PC1置换生成初始C0 D0
void init_key(char *key, char *c0, char *d0)
{
char cd[57] = { 0 };
char temp[65] = { 0 };
strcpy(temp, key);
// PC1置换
for (size_t i = 0; i < 56; i++) {
cd[i] = temp[pc1_table[i] - 1];
}
// printf("After PC1 switch: %s\n", cd);
// 将CD分解为C和D
for (size_t i = 0; i < 28; i++) {
c0[i] = cd[i];
d0[i] = cd[28 + i];
}
}
// 循环左移位操作
void ls_switch(char *str, int round)
{
int times = ls_table[round - 1];
char temp[28] = { 0 };
strcpy(temp, str);
for (size_t i = 0; i < 28; i++) {
str[i] = temp[(i + times) % 28];
}
}
// 合并左右字符串
void str_merge(char *left, char *right, char *out, int half_len)
{
for (size_t i = 0; i < half_len; i++) {
out[i] = left[i];
out[half_len + i] = right[i];
}
}
// 子密钥生成函数
void key_gen(char *key, char *c, char *d, int round, char *after_key)
{
// 进行循环左移位
ls_switch(c, round);
ls_switch(d, round);
// 将移位后的c、d合并到cd
char cd[57] = { 0 };
str_merge(c, d, cd, 28);
// PC2置换生成子密钥
for (size_t i = 0; i < 48; i++) {
after_key[i] = cd[pc2_table[i] - 1];
}
}
// DES加密
void des_encrypt(char *src, char *key, char *out)
{
char temp[65] = { 0 };
strcpy(temp, src);
// 进行IP置换
init_switch(temp);
char left[33] = { 0 };
char right[33] = { 0 };
// printf("After IP switch: %s\n", temp);
// 将明文分为左右两部分
for (size_t i = 0; i < 32; i++) {
left[i] = temp[i];
right[i] = temp[32 + i];
}
// printf("Left0: %s\n", left);
// printf("Right0: %s\n", right);
// PC1置换生成初始C0 D0
char c[29] = { 0 };
char d[29] = { 0 };
init_key(key, c, d);
// printf("C0: %s\n", c);
// printf("D0: %s\n", d);
// printf("------------------------\n");
// 进行十六轮加密
for (size_t round = 1; round < 17; round++) {
// E扩展运算
char er[49] = { 0 };
extend(right, er);
// printf("E%d: %s\n", round, er);
// 生成16轮密钥
char key_tmp[49] = { 0 };
key_gen(key, c, d, round, key_tmp);
// printf("Round %zu Key: %s\n", round, key_tmp);
// printf("C%d: %s\n", round, c);
// printf("D%d: %s\n", round, d);
// 密钥与E(R)异或得到结果res
char res[49] = { 0 };
xor(key_tmp, er, res, 48);
// printf("EK%d: %s\n", round, res);
// 进行S盒置换
char afters[64] = { 0 };
s_switch(res, afters);
// printf("S%d: %s\n", round, afters);
// 再进行P置换
char afterp[33] = { 0 };
p_switch(afters, afterp);
// printf("P%d: %s\n", round, afterp);
// 两边再异或
char r0[33] = { 0 };
xor(left, afterp, r0, 32);
strcpy(left, right);
strcpy(right, r0);
// printf("Left%d: %s\n", round, left);
// printf("Right%d: %s\n", round, right);
// printf("------------------------\n");
}
// 左右交换后合并
str_merge(right, left, temp, 32);
// 进行逆IP置换
re_ipswitch(temp);
// printf("After IP-1 switch: %s\n", temp);
strcpy(out, temp);
}
// DES解密
void des_decrypt(char *src, char *key, char *out)
{
char temp[65] = { 0 };
strcpy(temp, src);
char keys[16][65] = { 0 };
// 进行IP置换
init_switch(temp);
// 将密文分为左右两部分
char left[33] = { 0 };
char right[33] = { 0 };
for (size_t i = 0; i < 32; i++) {
left[i] = temp[i];
right[i] = temp[32 + i];
}
// PC1置换生成初始轮C0 D0
char c[29] = { 0 };
char d[29] = { 0 };
init_key(key, c, d);
// printf("C0: %s\n", c);
// printf("D0: %s\n", d);
// printf("------------------------\n");
// 生成十六轮密钥
for (size_t i = 0; i < 16; i++) {
key_gen(key, c, d, i + 1, keys[i]);
keys[i][48] = '\0';
}
// 解密
for (size_t round = 1; round < 17; round++) {
// E扩展运算
char er[49] = { 0 };
extend(right, er);
// printf("exr:\t%s\n", er);
// 密钥与E(R)异或得到结果res
char res[49] = { 0 };
xor(keys[16 - round], er, res, 48);
// printf("kxer:\t%s\n", res);
// 进行S盒置换
char afters[64] = { 0 };
s_switch(res, afters);
// printf("sw:\t%s\n", afters);
// 再进行P盒置换
char afterp[33] = { 0 };
p_switch(afters, afterp);
// printf("ps:\t%s\n", afterp);
// 两边再异或
char r0[33] = { 0 };
xor(left, afterp, r0, 32);
strcpy(left, right);
strcpy(right, r0);
// printf("l%d:\t%s\n", round, left);
// printf("r%d:\t%s\n", round, right);
// printf("------------------------\n");
}
// 左右交换后合并
str_merge(right, left, temp, 32);
// 进行逆IP置换
re_ipswitch(temp);
strcpy(out, temp);
}
int main()
{
char *src = "12345678";
char *key = "12345678";
char out_bin[64] = { 0 };
char out_hex[17] = { 0 };
char src_bin[65] = { 0 };
char key_bin[65] = { 0 };
// char src_bin[65] = "0110001101101111011011010111000001110101011101000110010101110010";
// char key_bin[65] = "0001001100110100010101110111100110011011101111001101111111110001";
// 明文转二进制
char src_hex[17] = { 0 };
single_byte_character_to_hex(src, src_hex);
hex2bin(src_hex, src_bin);
printf("Plaintext bin: %s\n", src_bin);
printf("Plaintext hex: %s\n", src_hex);
// 密钥转二进制
char key_hex[15] = { 0 };
single_byte_character_to_hex(key, key_hex);
hex2bin(key_hex, key_bin);
printf("Key bin: %s\n", key_bin);
printf("Key hex: %s\n", key_hex);
// 执行DES加密
des_encrypt(src_bin, key_bin, out_bin);
// 二进制转十六进制输出密文
bin2hex(out_bin, out_hex);
printf("Ciphertext bin: %s\n", out_bin);
printf("Ciphertext hex: %s\n", out_hex);
// 执行DES解密
char decrypted_bin[65] = { 0 };
char decrypted_hex[17] = { 0 };
des_decrypt(out_bin, key_bin, decrypted_bin);
// 二进制转十六进制输出明文
bin2hex(decrypted_bin, decrypted_hex);
printf("Decrypted bin: %s\n", decrypted_bin);
printf("Decrypted hex: %s\n", decrypted_hex);
return 0;
}
浙公网安备 33010602011771号