DES算法是一种典型的Feistel结构的分组密码算法,它的明文分组长度为64bit,密钥分组长度为64bit,其中有8bit是奇偶校验,所以有效密钥长度为56bit。DES算法的加密和解密采用同一过程,安全性依赖有效密钥。
DES算法加密过程
大致过程 : IP初始置换——16轮迭代变换——IP逆置换
1.需要输入的数据:
KEY:8字节密钥(64bit)
MIN:8字节明文(64bit)
相关介绍:
字节(Byte)是一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位。
字符是指计算机中使用的文字和符号,比如1 2 3 A B C a b c ~ ! · # 等等。
在不同编码中字符和字节的对应关系不同,
ASCII码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。
在加密过程中,是以64bit的形式进行变换的,即64位的二进制序列,所以要将输入的密钥和明文转化为64位二进制序列的形式
如:'a' 的ASCII值为97,将97转变为8位的二进制序列为 01100001
2 . IP初始置换:
将64位明文序列按下表进行置换(位置变换)
int IP_T[64] = //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
};
将置换后的数据 分成 L0(32bit),R0(32bit)两部分
3 . 16轮迭代变换
迭代过程:
如图所示: 下一轮的左半部分就是上一轮的右半部分,下一轮的右半部分 先由 上一轮右半部分与轮密钥Ki进行F函数变换,再与上一轮的左半部分异或得到,即如下列公式:
Li = Ri-1
Ri = Li-1 ⊕ F(Ri-1 , Ki)
3.1 轮密钥生成
1 . 64位秘钥降至56位秘钥,将密钥排成 8*8 的矩阵,每一行的第八位将作为奇偶校验位被忽略,于是形成了初始的56位的密钥
再通过置换表置换 PC-1(表中不含8,16,24,32,40,48,56,64这八个数),如下:
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.再将得到的56位密钥分成C0和D0,前28位为C0,后28位为D0
按循环左移表循环左移:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1
将循环左移后的Ci,Di合并,得到56位,再通过置换表PC-2,变为48位,即为轮密钥Ki:
PC-2
void PC_2(int input[56], int output[48])//PC_2
{
for (int i = 0; i<48; i++)
output[i] = input[PC2_T[i] - 1];
}
3.2 E盒扩展置换
将原来的明文数据的右半部分R从32位扩展成为48位,在两边扩展了两列 如下表进行扩展置换:
int E_T[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
};
将扩展后的 48bit 与得到的 46bit轮密钥 Ki 进行 异或,得到S盒的输入
3.3 S盒代替压缩
将48位数据按照每6位分为一组,一共分为8组,并分别输入S1, S2,S3,S4,S5,S6,S7,S8这8个盒子中,每个盒子产生4位的输出,将每个S 盒的输出拼接成32位。
每个盒子中的具体实现: 每组6bit,每组的第一位和最后一位构成的2位二进制数对应的十进制数为S盒的行号x,中间四位构成的4位二进制数对应的十进制数为S盒的列号y。在S盒中找到坐标为(x,y)的数,将这个10进制数化为4位的二进制数,即为此S盒输出的4bit。
int S_Box[8][4][16] = //8个S盒 ,每个盒为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
};
3.4 P盒置换
将S盒得到的32位数,按P盒进行置换
int PC2_T[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
};
4 . IP逆置换
经过16轮的迭代之后,将输出的L16和R16左右交换,合并起来形成64位的二进制数,最后 按照下表 进行IP逆置换,得到64bit密文
int IPR_T[64] = //逆IP置换矩阵
{
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
};
解密过程和加密一样。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int IP_T[64] = //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 E_T[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
};
int P_T[32] = // 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
};
int IPR_T[64] = //逆IP置换矩阵
{
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
};
int PC1_T[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
};
int PC2_T[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
};
int S_Box[8][4][16] = //8个S盒 每个盒为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
};
void CharToBit(char input[], int output[], int len) //把char转换为64二进制
{
for(int i=0;i<len;i++)
for(int j=0;j<8;j++)
output[8*i+7-j]=(input[i]>>j)&1;
}
void BitToChar(int intput[], char output[], int bits) //把64bit转换为8字节
{
for(int i=0;i<8;i++)
for(int j=0;j<8;j++)
output[i]=output[i]*2+intput[j+8*i];
}
void Xor(int A[], int B[], int len)//异或操作
{
for (int i = 0; i<len; i++)
A[i] = A[i]^ B[i];
}
void IP(int input[64], int output[64])//初始IP置换
{
for (int i = 0; i<64; i++)
output[i] = input[IP_T[i] - 1];
}
void E(int input[32], int output[48])//E扩展
{
for (int i = 0; i<48; i++)
output[i] = input[E_T[i] - 1];
}
void P(int input[32], int output[32])//P置换
{
for (int i = 0; i<32; i++)
output[i] = input[P_T[i] - 1];
}
void IP_In(int input[64], int output[64])//逆IP置换
{
for (int i = 0; i<64; i++)
output[i] = input[IPR_T[i] - 1];
}
void PC_1(const int input[64], int output[56]) //PC_1
{
for (int i = 0; i<56; i++)
output[i] = input[PC1_T[i] - 1];
}
void PC_2(int input[56], int output[48]) //PC_2
{
for (int i = 0; i<48; i++)
output[i] = input[PC2_T[i] - 1];
}
void S(int input[48], int output[32])//S盒压缩
{
int SI[8],k=0;
for (int i=0; i<48; i = i + 6)
SI[k] = S_Box[k++][(input[i] << 1) + (input[i + 5])][(input[i + 1] << 3) + (input[i + 2] << 2) + (input[i + 3] << 1) + (input[i + 4])];
for (int j = 0; j<8; j++)
for (int i = 0; i<4; i++)
output[4*j+3-i] = (SI[j] >> i) & 1;
}
void F_func(int input[32], int output[32], int subkey[48])//完成DES算法轮变换
{
int len = 48;
int temp[48] = { 0 },temp_1[32] = { 0 };
E(input, temp); //E盒扩展置换
Xor(temp, subkey, len); //与Ki异或
S(temp, temp_1); //S盒代替压缩
P(temp_1, output); //P盒置换
};
void RotateL(int input[28], int output[28], int leftCount) //秘钥循环左移
{
int len = 28;
for (int i = 0; i<len; i++)
output[i] = input[(i + leftCount) % len];
};
void subKey_fun(int input[64], int Subkey[16][48])//子密钥生成
{
int c[28], d[28];
int pc_1[56] = { 0 },pc_2[16][56] = { 0 };
int rotatel_c[16][28] = { 0 },rotatel_d[16][28] = { 0 };
PC_1(input, pc_1);
for (int i = 0; i<28; i++)
{
c[i] = pc_1[i];
d[i] = pc_1[i + 28];
}
int leftCount[17]={0,1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; //循环左移表
int ans=0;
for (int i = 1; i<=16; i++)
{
ans+=leftCount[i];
RotateL(c, rotatel_c[i - 1], ans);
RotateL(d, rotatel_d[i - 1], ans);
}
for (int i = 0; i<16; i++)
for (int j = 0; j<28; j++)
{
pc_2[i][j] = rotatel_c[i][j];
pc_2[i][j + 28] = rotatel_d[i][j];
}
for (int i = 0; i<16; i++)
PC_2(pc_2[i], Subkey[i]);
};
void DES_Efun(char input[8], char key_in[8], int output[64]) //加密
{
int Ip[64] = { 0 };//存储初始置换后的矩阵
int output_1[64] = { 0 }; //存储16轮迭代后,左右交换后合并的64bit
int subkeys[16][48]; //存16轮子密钥
int chartobit[64] = { 0 },l[17][32], r[17][32],key[64];
CharToBit(input, chartobit, 8); //转换为64个二进制数
IP(chartobit, Ip); //IP初始置换,Ip存置换后的数
CharToBit(key_in, key, 8); //密钥转换为64位二进制数
subKey_fun(key, subkeys); //密钥变换
for (int i = 0; i<32; i++)
{
l[0][i] = Ip[i];
r[0][i] = Ip[32 + i];
}
for (int i = 1; i<=16; i++)//16轮的迭代操作
{
for (int k = 0; k<32; k++) //下一轮的左半部分就是上一轮的右半部分
l[i][k] = r[i - 1][k];
F_func(r[i - 1], r[i], subkeys[i - 1]);
Xor(r[i], l[i - 1], 32);
}
for (int t = 0; t<32; t++) //将16轮迭代后的32bit左右置换并合并
{
output_1[t] = l[16][t];
output_1[32 + t] = r[16][t];
}
IP_In(output_1, output); //IP逆置换
};
void DES_Dfun(int input[64], char key_in[8], char output[8]) //DES解密
{
int Ip[64] = { 0 };//存储初始置换后的矩阵
int output_1[64] = { 0 },output_2[64] = { 0 };
int subkeys[16][48]; //存16轮子密钥
int chartobit[64] = { 0 };
int key[64],l[17][32], r[17][32];
IP(input, Ip); //IP初始置换
CharToBit(key_in, key, 8); //密钥转变为64位2进制数列
subKey_fun(key, subkeys); //求16轮子密钥
for (int i = 0; i<32; i++)
{
l[0][i] = Ip[i];
r[0][i] = Ip[32 + i];
}
for (int j = 1; j<=16; j++)//16轮的迭代操作
{
for (int k = 0; k<32; k++)
l[j][k] = r[j - 1][k];
F_func(r[j - 1], r[j], subkeys[16 - j]);
Xor(r[j], l[j - 1], 32);
}
for (int t = 0; t<32; t++) //将16轮迭代后的32bit左右置换并合并
{
output_1[t] = l[16][t];
output_1[32 + t] = r[16][t];
}
IP_In(output_1, output_2); //IP逆置换
BitToChar(output_2, output, 8); //转变为字符形式
};
int main()
{
while(1)
{
int n,output[64]= {0};
char MIN[10]= {0};
char KEY[10]= {0};
char MI[65]={0};
printf("1:明文加密 2:密文解密 0:结束使用\n选择功能: ");
scanf("%d",&n);
if(n==0) break;
else if(n==1)
{
printf("请输入明文(8字节)\n");
scanf("%s",MIN);
printf("请输入密钥(8字节)\n");
scanf("%s",KEY);
DES_Efun(MIN, KEY, output);
printf("密文如下:\n");
for (int i = 0; i<64; i++)
{
printf("%d", output[i]);
if ((i + 1) % 8 == 0)
printf("\n");
}
printf("\n");
}
else if(n==2)
{
printf("请输入密文(8字节)\n");
scanf("%s",MI);
for(int i=0;i<64;i++)
output[i]=MI[i]-'0';
printf("请输入密钥(8字节)\n");
scanf("%s",KEY);
DES_Dfun(output, KEY, MIN);
printf("明文如下:\n");
for (int i = 0; i<8; i++)
printf("%c", MIN[i]);
printf("\n\n");
}
}
return 0;
}