DES算法笔记

DES算法笔记

参考文献:原文链接:https://blog.csdn.net/qq_27570955/article/details/52442092

​ 代码链接:https://blog.csdn.net/zidane_2014/article/details/37988657

一级目录

二级目录

三级目录

前言:大二小白第一篇博客,纯属搬轮子,东西很复杂,没啥好看的,纯属自娱自乐(为了写报告),有做的不足请见谅,以此纪念;

先上代码调试截图:(若有中文乱码问题,请自行解决233。。。。)

在这里插入图片描述

1.所需参数

  • key: 8个字节共64位的工作密钥
  • data :8个字节共64位的需要被加密或被解密的数据
  • mode :DES工作方式,加密或者解密
  • 代码:main方法:
int main()
{
	int output[64] = { 0 };
	char MIN[9] = { 0 };//存储8个字节也就是64位明码
	char MI[9] = { 0 };//存储8个字节也就是64位密钥
	printf("请输入明文(8字节)\n");
	gets_s(MIN);//从控制台输入
	printf("请输入秘钥(8字节)\n");
	gets_s(MI);//从控制台输入
	DES_Efun(MIN, MI, output);
	printf("密文如下:\n");
	for (int i = 0; i<64; i++)
	{
		printf("%d", output[i]);
		if ((i + 1) % 4 == 0)
			printf("\n");
	}
	printf("\n");
 
        for(int i=0;i<8;i++) MIN[i]='0';
	printf("解密功能\n");
	DES_Dfun(output, MI, MIN);
	printf("明文如下:\n");
	for (int i = 0; i<8; i++)
	{
		printf("%c", MIN[i]);
	}
	printf("\n\n");
	return 0;
}

调试截图:(这里输入明文为“11111111”,密钥为“12345678”)

在这里插入图片描述

加密过程代码:

static void  DES_Efun(char input[8], char key_in[8], int output[64])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵  
	int output_1[64] = { 0 };
	int subkeys[16][48];
	int chartobit[64] = { 0 };
	int key[64];
	int l[17][32], r[17][32];
	CharToBit(input, chartobit, 8);//正确,转换为64个二进制数的操作正确!  
	IP(chartobit, Ip, IP_Table);//正确,IP初始置换!
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!  
	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++)//前15轮的操作
	{
		for (int k = 0; k<32; k++)
		{
			l[j][k] = r[j - 1][k];
		}
		F_func(r[j - 1], r[j], subkeys[j - 1]);
		Xor(r[j], l[j - 1], 32);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[15]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output, IPR_Table);
};

2.初始置换

DES算法使用64位的密钥key将64位的明文输入块变为64位的密文输出块,并把输出块分为L0、R0两部分,每部分均为32位。初始置换规则如下:

注意:这里的数字表示的是原数据的位置,不是数据

static void CharToBit(const char input[], int output[], int bits)//把CHAR转换为INT 
{
	int i, j;
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<8; i++)
		{
			output[7 * (j + 1) - i + j] = (input[j] >> i) & 1;
		}
	}
};

调试截图:

这里我们可以看到用来存储64为明文的数组已经将8个字节转换成64位

然后开始IP置换:

static  void IP(const int input[64], int output[64], int table[64])//初始IP置换 
{
	int i;
	for (i = 0; i<64; i++)
	{
		output[i] = input[table[i] - 1];//减1操作不可少!!
	}
};

以下是IP置换的规则:

int IP_Table[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 };

经过第一次初始IP置换后,IP数组中存储量置换后的矩阵

调试截图:

在这里插入图片描述

即将输入的64位明文的第1位置换到第40位,第2位置换到第8位,第3位置换到第48位。以此类推,最后一位是原来的第7位。置换规则是规定的。L0(Left)是置换后的数据的前32位,R0(Right)是置换后的数据的后32位。

例如:64位输入块是D1~D64,则经过初始置换后是D58,D50…D7。则L0=D58,D50,D12…D8;R0=D57,D49,D41…D7。

该置换过程是在64位秘钥的控制下。

3.加密处理–迭代过程

经过初始置换后,进行16轮完全相同的运算,在运算过程中数据与秘钥结合。

函数f的输出经过一个异或运算,和左半部分结合形成新的右半部分,原来的右半部分成为新的左半部分。每轮迭代的过程可以表示如下:

Ln = R(n - 1);

Rn = L(n - 1)⊕f(Rn-1,kn-1)

⊕:异或运算

Kn是向第N层输入的48位的秘钥,f是以Rn-1和Kn为变量的输出32位的函数

3.1函数f

函数f由四步运算构成:秘钥置换(Kn的生成,n=0~16);扩展置换;S-盒代替;P-盒置换。

3.1.1 秘钥置换–子密钥生成

DES算法由64位秘钥产生16轮的48位子秘钥。在每一轮的迭代过程中,使用不同的子秘钥。

a、把密钥的奇偶校验位忽略不参与计算,即每个字节的第8位,将64位密钥降至56位,然后根据选择置换PC-1将这56位分成两块C0(28位)和D0(28位);

b、将C0和D0进行循环左移变化(注:每轮循环左移的位数由轮数决定),变换后生成C1和D1,然后C1和D1合并,并通过选择置换PC-2生成子密钥K1(48位);

c、C1和D1在次经过循环左移变换,生成C2和D2,然后C2和D2合并,通过选择置换PC-2生成密钥K2(48位);

d、以此类推,得到K16(48位)。但是最后一轮的左右两部分不交换,而是直接合并在一起R16L16,作为逆置换的输入块。其中循环左移的位数一共是循环左移16次,其中第一次、第二次、第九次、第十六次是循环左移一位,其他都是左移两位。

3.1.2 密钥置换选择1—PC-1(子秘钥的生成)

*操作对象是64位秘钥*

64位秘钥降至56位秘钥不是说将每个字节的第八位删除,而是通过缩小选择换位表1(置换选择表1)的变换变成56位。如下:

注意:这里的数字表示的是原数据的位置,不是数据

代码:

static  void PC_1(const int input[64], int output[56], int table[56])//PC_1  
{
	int i;
	for (i = 0; i<56; i++)
	{
		output[i] = input[table[i] - 1];//64位将至56位
	}
};
for (int i = 0; i<32; i++)//这里将56位秘钥分成C0和D0
	{
		l[0][i] = Ip[i];
		r[0][i] = Ip[32 + i];
	}

调试截图:

在这里插入图片描述

根据轮数,将Cn和Dn分别循环左移1位或2位

循环左移每轮移动的位数如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0Di7aIB-1587295756294)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200419171048092.png)]

代码实现:

for (i = 1; i<17; i++)
	{
		if (i == 1 || i == 2 || i == 9 || i == 16)
		{
			leftCount += loop;
			RotateL(c, rotatel_c[i - 1], leftCount);
			RotateL(d, rotatel_d[i - 1], leftCount);
		}
		else
		{
			leftCount += loop_2;
			RotateL(c, rotatel_c[i - 1], leftCount);
			RotateL(d, rotatel_d[i - 1], leftCount);
		}
	}

C1和D1合并之后,再经过置换选择表2生成48位的子秘钥K1。**置换选择表2(PC-2)**如下:

去掉第9、18、22、25、35、38、43、54位,从56位变成48位,再按表的位置置换

C1和D1再次经过循环左移变换,生成C2和D2,C2和D2合并,通过PC-2生成子秘钥K2

代码:

//c1和c2循环左移变换
for (i = 0; i<16; i++)
	{
		for (j = 0; j<28; j++)
		{
			pc_2[i][j] = rotatel_c[i][j];
			pc_2[i][j + 28] = rotatel_d[i][j];
		}
	}
	for (i = 0; i<16; i++)
	{
		PC_2(pc_2[i], Subkey[i], PC2_Table);
	}
static  void PC_2(const int input[56], int output[48], int table[48])//PC_2  
{
	int i;
	for (i = 0; i<48; i++)
	{
		output[i] = input[table[i] - 1];
	}
};

调试截图:

在这里插入图片描述

以此类推,得到子秘钥K1~K16。需要注意其中循环左移的位数。

3.1.2 扩展置换E(E位选择表)

通过扩展置换E,数据的右半部分Rn从32位扩展到48位。扩展置换改变了位的次序,重复了某些位。

扩展置换的目的:a、产生与秘钥相同长度的数据以进行异或运算,R0是32位,子秘钥是48位,所以R0要先进行扩展置换之后与子秘钥进行异或运算;b、提供更长的结果,使得在替代运算时能够进行压缩。

扩展置换E规则如下:

在这里插入图片描述

​ 代码实现:

E_table扩展矩阵:

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 };
static  void E(const int input[32], int output[48], int table[48])//E扩展  
{
	int i;
	for (i = 0; i<48; i++)
	{
		output[i] = input[table[i] - 1];
	}
};

3.1.3 S-盒代替(功能表S盒)

Rn扩展置换之后与子秘钥Kn异或以后的结果作为输入块进行S盒代替运算
功能是把48位数据变为32位数据

代替运算由8个不同的代替盒(S盒)完成。每个S-盒有6位输入,4位输出。

所以48位的输入块被分成8个6位的分组,每一个分组对应一个S-盒代替操作。

经过S-盒代替,形成8个4位分组结果。

注意:每一个S-盒的输入数据是64位,输出数据是4位,但是每个S-盒自身是64位!!
每个S-和是4行16列的格式,因为二进制4位是0~15。8个S-盒的值如下:

int S_Box[8][4][16] = {                     //8个S盒   三维数组  
											// 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
};

S-盒计算过程

以S-盒8为例子,

假设S-盒8的输入(即异或函数的第43~18位)为110011。

在这里插入图片描述

第1位和最后一位组合形成了11(二进制),对应S-盒8的第3行。中间的4位组成形成1001(二进制),对应S-盒8的第9列。所以对应S-盒8第3行第9列值是12。则S-盒输出是1100(二进制)。

代码实现:

static  void S(const int input[48], int output[32], int table[8][4][16])//S盒压缩 
{
	int i = 0;
	int j = 0;
	int INT[8];
	for (; i<48; i = i + 6)
	{
		INT[j] = table[j][(input[i] << 1) + (input[i + 5])][(input[i + 1] << 3) + (input[i + 2] << 2) + (input[i + 3] << 1) + (input[i + 4])];
		j++;
	}
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<4; i++)
		{
			output[3 * (j + 1) - i + j] = (INT[j] >> i) & 1;
		}
	}
};

3.1.4 P-盒置换

S-盒代替运算,每一盒得到4位,8盒共得到32位输出。这32位输出作为P盒置换的输入块。

P盒置换将每一位输入位映射到输出位。任何一位都不能被映射两次,也不能被略去。

经过P-盒置换的结果与最初64位分组的左半部分异或,然后左右两部分交换,开始下一轮迭代。

P-盒置换表(表示数据的位置)共32位
将32位的输入的第16位放在第一位,第七位放在第二位,第二十位放在第三位,以此类推.

代码实现:

static  void P(const int input[32], int output[32], int table[32])//P置换 
{
	int i;
	for (i = 0; i<32; i++)
	{
		output[i] = input[table[i] - 1];
	}
};

逆置换

将初始置换进行16次的迭代,即进行16层的加密变换,这个运算过程我们暂时称为函数f。得到L16和R16,将此作为输入块,进行逆置换得到最终的密文输出块。逆置换是初始置换的逆运算。从初始置换规则中可以看到,原始数据的第1位置换到了第40位,第2位置换到了第8位。则逆置换就是将第40位置换到第1位,第8位置换到第2位。

注意:DES算法的加密密钥是根据用户输入的秘钥生成的,该算法把64位密码中的第8位、第16位、第24位、第32位、第40位、第48位、第56位、第64位作为奇偶校验位,在计算密钥时要忽略这8位.所以实际中使用的秘钥有效位是56位。详情计算看本文的3.1.2秘钥置换选择。

秘钥共64位,每次置换都不考虑每字节的第8位,因为这一位是奇偶校验位,所以64位秘钥的第8、16、24、32、40、48、56、64位在计算秘钥时均忽略。

代码实现:

for (int j = 1; j<16; j++)//前15轮的操作  
	{
		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);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作  
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[0]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output_2, IPR_Table);
	BitToChar(output_2, output, 8);
};

4.DES算法描述

1)、输入64位明文数据,并进行初始置换IP;

2)、在初始置换IP后,明文数据再被分为左右两部分,每部分32位,以L0,R0表示;

3)、在秘钥的控制下,经过16轮运算(f);

4)、16轮后,左、右两部分交换,并连接再一起,

5)、输出64位密文。

代码实现:

static void  DES_Efun(char input[8], char key_in[8], int output[64])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵  
	int output_1[64] = { 0 };
	int subkeys[16][48];16个子密钥
	int chartobit[64] = { 0 };//64位明文
	int key[64];//64位密钥
	int l[17][32], r[17][32];//左半部分,右半部分
	CharToBit(input, chartobit, 8);//正确,转换为64个二进制数的操作正确!  
	IP(chartobit, Ip, IP_Table);//正确,IP初始置换!  
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!  
	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++)//前15轮的操作  
	{
		for (int k = 0; k<32; k++)
		{
			l[j][k] = r[j - 1][k];
		}
		F_func(r[j - 1], r[j], subkeys[j - 1]);
		Xor(r[j], l[j - 1], 32);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作  
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[15]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output, IPR_Table);
};

5.DES解密

加密和解密可以使用相同的算法。加密和解密唯一不同的是秘钥的次序是相反的。就是说如果每一轮的加密秘钥分别是K1、K2、K3…K16,那么解密秘钥就是K16、K15、K14…K1。为每一轮产生秘钥的算法也是循环的。加密是秘钥循环左移,解密是秘钥循环右移。解密秘钥每次移动的位数是:0、1、2、2、2、2、2、2、1、2、2、2、2、2、2、1。

代码实现:

static void  DES_Dfun(int input[64], char key_in[8], char output[8])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵  
	int output_1[64] = { 0 };
	int output_2[64] = { 0 };
	int subkeys[16][48];
	int chartobit[64] = { 0 };
	int key[64];
	int l[17][32], r[17][32];
	IP(input, Ip, IP_Table);//正确,IP初始置换!  
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!  
	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++)//前15轮的操作  
	{
		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);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作  
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[0]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output_2, IPR_Table);
	BitToChar(output_2, output, 8);
};

6.DES算法特点

1、分组加密算法:

以64位为分组。64位明文输入,64位密文输出。

2、对称算法:

加密和解密使用同一秘钥

3、有效秘钥长度为56位

秘钥通常表示为64位数,但每个第8位用作奇偶校验,可以忽略。

4、代替和置换

DES算法是两种加密技术的组合:混乱和扩散。先替代后置换。

5、易于实现

DES算法只是使用了标准的算术和逻辑运算,其作用的数最多也只有64 位,因此用70年代末期的硬件技术很容易实现

算法的重复特性使得它可以非常理想地用在一个专用芯片中。

7 秘钥算法的特点

优点:

效率高,算法简单,系统开销小

适合加密大量数据

明文长度和密文长度相等

缺点:

需要以安全方式进行秘钥交换

秘钥管理复杂

8.附上全部代码:


#include<stdio.h>  
#include<string.h>  
//#define gets_s gets   //出现[Error] 'gets_s' was not declared in this scope的话就加上这句,默认使用的gcc编译器的话会出现此错误,因为gets_s是vs提供的函数
int IP_Table[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_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 };
int P_Table[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_Table[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_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 };
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 };
int S_Box[8][4][16] = {                     //8个S盒   三维数组 
											// 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
};
static void CharToBit(const char input[], int output[], int bits)//把CHAR转换为INT 
{
	int i, j;
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<8; i++)
		{
			output[7 * (j + 1) - i + j] = (input[j] >> i) & 1;
		}
	}
};
static void BitToChar(const int intput[], char output[], int bits)//把INT转换为CHAR  
{
	int i, j;
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<8; i++)
		{
			output[j] = output[j] * 2 + intput[i + 8 * j];
		}
	}
};
static void Xor(int *INA, int *INB, int len)//异或操作  
{
	int i;
	for (i = 0; i<len; i++)
	{
		*(INA + i) = *(INA + i) ^ *(INB + i);
	}
};
static  void IP(const int input[64], int output[64], int table[64])//初始IP置换 
{
	int i;
	for (i = 0; i<64; i++)
	{
		output[i] = input[table[i] - 1];//减1操作不可少!!
	}
};
static  void E(const int input[32], int output[48], int table[48])//E扩展 
{
	int i;
	for (i = 0; i<48; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void P(const int input[32], int output[32], int table[32])//P置换 
{
	int i;
	for (i = 0; i<32; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void IP_In(const int input[64], int output[64], int table[64])//逆IP  
{
	int i;
	for (i = 0; i<64; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void PC_1(const int input[64], int output[56], int table[56])//PC_1  
{
	int i;
	for (i = 0; i<56; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void PC_2(const int input[56], int output[48], int table[48])//PC_2  
{
	int i;
	for (i = 0; i<48; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void S(const int input[48], int output[32], int table[8][4][16])//S盒压缩 
{
	int i = 0;
	int j = 0;
	int INT[8];
	for (; i<48; i = i + 6)
	{
		INT[j] = table[j][(input[i] << 1) + (input[i + 5])][(input[i + 1] << 3) + (input[i + 2] << 2) + (input[i + 3] << 1) + (input[i + 4])];
		j++;
	}
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<4; i++)
		{
			output[3 * (j + 1) - i + j] = (INT[j] >> i) & 1;
		}
	}
};
static void F_func(int input[32], int output[32], int subkey[48])//完成DES算法轮变换  
{
	int len = 48;
	int temp[48] = { 0 };
	int temp_1[32] = { 0 };
	E(input, temp, E_Table);
	Xor(temp, subkey, len);
	S(temp, temp_1, S_Box);
	P(temp_1, output, P_Table);
};
static void RotateL(const int input[28], int output[28], int leftCount)//秘钥循环左移  
{
	int i;
	int len = 28;
	for (i = 0; i<len; i++)
	{
		output[i] = input[(i + leftCount) % len];
	}
};
static void  subKey_fun(const int input[64], int Subkey[16][48])//子密钥生成  
{
	int loop = 1, loop_2 = 2;
	int i, j;
	int c[28], d[28];
	int pc_1[56] = { 0 };
	int pc_2[16][56] = { 0 };
	int rotatel_c[16][28] = { 0 };
	int rotatel_d[16][28] = { 0 };
	PC_1(input, pc_1, PC1_Table);
	for (i = 0; i<28; i++)
	{
		c[i] = pc_1[i];
		d[i] = pc_1[i + 28];
	}
	int leftCount = 0;
	for (i = 1; i<17; i++)
	{
		if (i == 1 || i == 2 || i == 9 || i == 16)
		{
			leftCount += loop;
			RotateL(c, rotatel_c[i - 1], leftCount);
			RotateL(d, rotatel_d[i - 1], leftCount);
		}
		else
		{
			leftCount += loop_2;
			RotateL(c, rotatel_c[i - 1], leftCount);
			RotateL(d, rotatel_d[i - 1], leftCount);
		}
	}
	for (i = 0; i<16; i++)
	{
		for (j = 0; j<28; j++)
		{
			pc_2[i][j] = rotatel_c[i][j];
			pc_2[i][j + 28] = rotatel_d[i][j];
		}
	}
	for (i = 0; i<16; i++)
	{
		PC_2(pc_2[i], Subkey[i], PC2_Table);
	}
};
static void  DES_Efun(char input[8], char key_in[8], int output[64])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵  
	int output_1[64] = { 0 };
	int subkeys[16][48];//16个子密钥
	int chartobit[64] = { 0 };//64位明文
	int key[64];//64位密钥
	int l[17][32], r[17][32];//左半部分,右半部分
	CharToBit(input, chartobit, 8);//正确,转换为64个二进制数的操作正确!  
	IP(chartobit, Ip, IP_Table);//正确,IP初始置换!
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!  
	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++)//前15轮的操作
	{
		for (int k = 0; k<32; k++)
		{
			l[j][k] = r[j - 1][k];
		}
		F_func(r[j - 1], r[j], subkeys[j - 1]);
		Xor(r[j], l[j - 1], 32);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[15]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output, IPR_Table);
};
static void  DES_Dfun(int input[64], char key_in[8], char output[8])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵 
	int output_1[64] = { 0 };
	int output_2[64] = { 0 };
	int subkeys[16][48];
	int chartobit[64] = { 0 };
	int key[64];
	int l[17][32], r[17][32];
	IP(input, Ip, IP_Table);//正确,IP初始置换!
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!
	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++)//前15轮的操作  
	{
		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);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作  
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[0]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output_2, IPR_Table);
	BitToChar(output_2, output, 8);
};
int main()
{
	int output[64] = { 0 };
	char MIN[9] = { 0 };
	char MI[9] = { 0 };
	printf("请输入明文(8字节)\n");
	gets_s(MIN);
	printf("请输入秘钥(8字节)\n");
	gets_s(MI);
	DES_Efun(MIN, MI, output);
	printf("密文如下:\n");
	for (int i = 0; i<64; i++)
	{
		printf("%d", output[i]);
		if ((i + 1) % 4 == 0)
			printf("\n");
	}
	printf("\n");
 
        for(int i=0;i<8;i++) MIN[i]='0';//评论区见到有人不服,没看懂函数就说删掉解密部分输出明文没变,那就在解密前加上个赋值,你再试试?
 
	printf("解密功能\n");
	DES_Dfun(output, MI, MIN);
	printf("明文如下:\n");
	for (int i = 0; i<8; i++)
	{
		printf("%c", MIN[i]);
	}
	printf("\n\n");
	return 0;
}
	F_func(r[j - 1], r[j], subkeys[16 - j]);
	Xor(r[j], l[j - 1], 32);
}
int t = 0;
for (t = 0; t<32; t++)//最后一轮的操作  
{
	r[16][t] = r[15][t];
}
F_func(r[15], l[16], subkeys[0]);
Xor(l[16], l[15], 32);
for (t = 0; t<32; t++)
{
	output_1[t] = l[16][t];
	output_1[32 + t] = r[16][t];
}
IP_In(output_1, output_2, IPR_Table);
BitToChar(output_2, output, 8);

};
int main()
{
int output[64] = { 0 };
char MIN[9] = { 0 };
char MI[9] = { 0 };
printf(“请输入明文(8字节)\n”);
gets_s(MIN);
printf(“请输入秘钥(8字节)\n”);
gets_s(MI);
DES_Efun(MIN, MI, output);
printf(“密文如下:\n”);
for (int i = 0; i<64; i++)
{
printf("%d", output[i]);
if ((i + 1) % 4 == 0)
printf("\n");
}
printf("\n");

    for(int i=0;i<8;i++) MIN[i]='0';//评论区见到有人不服,没看懂函数就说删掉解密部分输出明文没变,那就在解密前加上个赋值,你再试试?

printf("解密功能\n");
DES_Dfun(output, MI, MIN);
printf("明文如下:\n");
for (int i = 0; i<8; i++)
{
	printf("%c", MIN[i]);
}
printf("\n\n");
return 0;

}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值