一.DES算法简介

DES(Data Encryption Standard)是目前最为流行的加密算法之一。

对称性:DES是对称的,也就是说它使用同一个密钥来加密和解密数据。与此相对的是RSA加密算法,是一种非对称加密算法

分组性:DES还是一种分组加密算法,该算法每次处理固定长度的数据段,称之为分组。DES分组的大小是64位,如果加密的数据长度不是64位的倍数,可以按照某种具体的规则来填充位。

“混乱和扩散”的原则:混乱的目的是为隐藏任何明文同密文、或者密钥之间的关系,而扩散的目的是使明文中的有效位和密钥一起组成尽可能多的密文。两者结合到一起就使得安全性变得相对较高。

DES算法具体通过对明文进行一系列的排列和替换操作来将其加密:过程的关键就是从给定的初始密钥中得到16个子密钥的函数。要加密一组明文,每个子密钥按照顺序(1-16)以一系列的位操作施加于数据上,每个子密钥一次,一共重复16次。每一次迭代称之为一轮。要对密文进行解密可以采用同样的步骤,只是子密钥是按照逆向的顺序(16-1)对密文进行处理。

DES加密后解密中文乱码 des加密解密原理_异或运算

二.DES算法入口参数

key:7个字节共56位的工作密钥

data:8个字节共64位的需要被加密或被解密的数据

mode:DES工作方式,加密或者解密

三.算法步骤

DES加密后解密中文乱码 des加密解密原理_数据_02

1.初始置换

其功能是把输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长32位,其置换规则为将输入的第58位换到第一位,第50位换到第2位……依此类推,最后一位是原来的第7位。L0、R0则是换位输出后的两部分,L0是输出的左32位,R0是右32位

例:设置换前的输入值为D1D2D3……D64,则经过初始置换后的结果为:L0=D58D50……D8;R0=D57D49……D7。L0(Left)是置换后的数据的前32位,R0(Right)是置换后的数据的后32位。

DES加密后解密中文乱码 des加密解密原理_异或运算_03

DES加密后解密中文乱码 des加密解密原理_数据_04

2.加密处理--迭代过程

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

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

Ln = R(n - 1);

Rn = L(n - 1)⊕g(Rn-1,kn-1);    ⊕:异或运算

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

DES加密后解密中文乱码 des加密解密原理_DES加密后解密中文乱码_05

DES加密后解密中文乱码 des加密解密原理_数据_06

DES加密后解密中文乱码 des加密解密原理_数据_07

2.1函数g

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

2.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次,其中第一次、第二次、第九次、第十六次是循环左移一位,其他都是左移两位。

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

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

DES加密后解密中文乱码 des加密解密原理_迭代_08

 

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

DES加密后解密中文乱码 des加密解密原理_数据_09

第一轮是循环左移1位。C0循环左移1位后得到C1如下:

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,57

D0循环左移1位后得到D1如下:

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,63

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

去掉第9、18、22、25、35、38、43、54位,从56位变成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

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

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

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

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

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

扩展置换E规则如下:

DES加密后解密中文乱码 des加密解密原理_DES加密后解密中文乱码_10

2.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-盒的值如下:

S-盒1
 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,S-盒2
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,S-盒3
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,S-盒4
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,S-盒5
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,S-盒6
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,S-盒7
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,S-盒8
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-盒计算过程:以盒8为例

DES加密后解密中文乱码 des加密解密原理_迭代_11

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

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

2.1.4 P-盒置换

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

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

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

P-盒置换表(表示数据的位置)共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,

3.逆置换

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

DES加密后解密中文乱码 des加密解密原理_数据_12

4.DES算法描述

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

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

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

4.16轮后,左、右两部分交换,并连接再一起,再进行逆置换;

5.输出64位密文。

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

四.C++代码实现

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

void main()
{ //声明变量
	char MingWen[104]; //存放原始的明文
	char target[8]; //将明文断成8个字符的一个分组
	char InputKey[9]; //存放字符型的八位密钥
	int text[64]; //存放一个分组转成二进制后的数据
	int text_ip[64]; //存放第一次初始换位的结果
	int L0[32], Li[32]; //将64位分成左右各32位进行迭代
	int R0[32], Ri[32];
	int RE0[48]; //存放右半部分经过E表扩展换位后的48位数据
	int key[64]; //存放密钥的二进制形式
	int keyPC1[56]; //存放密钥key经过PC1换位表后变成的56位二进制
	int A[28]; //将keyPC1分成左右两部分,左部A,右部B,各28位,以便进行循环左移
	int B[28];
	int keyAB[56]; //将循环左移后两部分的结果合并起来
	int K[16][48]; //存放16次循环左移产生的子密钥
	int RK[48]; //存放RE和K异或运算后的结果
	int RKS[8]; //存放经过查找8个S表后得到的8个十进制结果
	int SP[32]; //将RKS表中的十进制数化成二进制
	int RKSP[32]; //存放SP表经过P盒换位后的结果
	int text_end[64]; //存放经过左右32位换位后的结果
	int text_out[14][64]; //存放初始化向量和所有经过DES的分组的二进制
	char init[9] = { "HTmadeit" }; //设置初始化向量为“HTmadeit”
	int CBC[64];
	int result[13][64];
	int H[208];
	char MiWen[208];
	int C[832];
	int M[13][8];

	char choice;
	int t;
	int i, j;
	int k, l, m, n;
	int r[8], c[8];
	int flag = 1;

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

	int E[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 PC1[56] = { //PC1换位表(64—>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 move[16] = { //循环移位表
		1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };

	int PC2[48] = { //PC2换位表(56—>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 S1[4][16] = { //S换位表
		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
	};
	int S2[4][16] = {
		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
	};
	int S3[4][16] = {
		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
	};
	int S4[4][16] = {
		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
	};
	int S5[4][16] = {
		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
	};
	int S6[4][16] = {
		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
	};
	int S7[4][16] = {
		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
	};
	int S8[4][16] = {
		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
	};
	int P[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
	};

	printf("HYs-des加密/解密\n\n");
	while (flag)
	{
		printf("A加密,B解密,请选择:\n");
		scanf("%c", &choice);

		while (choice != 'A' && choice != 'B' && choice != 'a' && choice != 'b')
		{
			printf("对不起,您的输入不合法。请选择A或B,A表示加密,B表示解密。\n");
			scanf("%c", &choice);
		}
		getchar();

		//生成子密钥
		printf("请输入8位密钥:\n");
		gets_s(InputKey);
		while (InputKey[7] == '\0' || InputKey[8] != '\0')
		{
			printf("您输入的密钥位数有误,请重新输入8位密钥:\n");
			gets_s(InputKey);
		}

		for (i = 0; i < 8; i++) //将密钥转化成64位二进制数放到一维数组key中
		{
			int a[8] = { 0,0,0,0,0,0,0,0 };
			m = InputKey[i];
			for (j = 0; m != 0; j++)
			{
				a[j] = m % 2;
				m = m / 2;
			}
			for (j = 0; j < 8; j++)
				key[(i * 8) + j] = a[7 - j];
		}

		//for(i=0;i<64;i++)
		//printf("%d,",key[i]);

		for (i = 0; i < 56; i++) //通过PC1换位表变成56位密钥放在keyPC1中
			keyPC1[i] = key[PC1[i] - 1];

		for (i = 0; i < 28; i++) //分成A和B两部分,各28位
		{
			A[i] = keyPC1[i];
			B[i] = keyPC1[i + 28];
		}

		for (t = 0; t < 16; t++)
		{
			if (move[t] == 1) //按照循环移位表将Ai和Bi分别左移move[t]位
			{
				n = A[0];
				for (i = 0; i < 27; i++)
					A[i] = A[i + 1];
				A[27] = n;
				n = B[0];
				for (i = 0; i < 28; i++)
					B[i] = B[i + 1];
				B[27] = n;
			}
			else
			{
				n = A[0];
				m = A[1];
				for (i = 0; i < 26; i++)
					A[i] = A[i + 2];
				A[26] = n;
				A[27] = m;
				n = B[0];
				m = B[1];
				for (i = 0; i < 26; i++)
					B[i] = B[i + 2];
				B[26] = n;
				B[27] = m;
			}

			for (i = 0; i < 28; i++) //将A和B合并成56位
			{
				keyAB[i] = A[i];
				keyAB[i + 28] = B[i];
			}

			for (i = 0; i < 48; i++) //通过PC2换位表变成48位密钥
				K[t][i] = keyAB[PC2[i] - 1];
		}

		//for(t=0;t<16;t++) 
		//for(i=0;i<48;i++)
		// printf("%d,",K[t][i]);

		for (i = 0; i < 8; i++) //将初始化向量转化成二进制数储存到数组text_out的第一行中
		{
			int a[8] = { 0,0,0,0,0,0,0,0 };
			m = init[i];
			for (j = 0; m != 0; j++)
			{
				a[j] = m % 2;
				m = m / 2;
			}
			for (j = 0; j < 8; j++)
				text_out[0][(i * 8) + j] = a[7 - j];
		}


		//加密程序

		if (choice == 'A' || choice == 'a')
		{
			printf("请输入您想加密的内容:\n"); //输入明文
			gets_s(MingWen);
			while (MingWen[0] == '\0')
			{
				printf("对不起,明文不可为空,请您输入正确的明文。\n");
				gets_s(MingWen);
			}

			//CBC模式下的加密
			i = 0; //将明文每8个字符作为一个分组,共有n个分组
			n = 0;
			while (MingWen[i] != '\0')
			{
				n++;
				i++;
			}
			k = n % 8;
			n = (n - 1) / 8 + 1;

			for (l = 0; l < n; l++)
			{
				if (l == (n - 1) && k != 0)
				{
					for (i = 0; i < k; i++) //将每个分组的8个字符放到数组target中,不够的用空格补充
						target[i] = MingWen[i + (8 * l)];
					for (i = k; i < 8; i++)
						target[i] = ' ';
				}
				else
					for (i = 0; i < 8; i++)
						target[i] = MingWen[i + (8 * l)];

				for (i = 0; i < 8; i++) //将得到的明文转化成二进制数储存到数组text中
				{
					int a[8] = { 0,0,0,0,0,0,0,0 };
					m = target[i];
					for (j = 0; m != 0; j++)
					{
						a[j] = m % 2;
						m = m / 2;
					}
					for (j = 0; j < 8; j++)
						text[(i * 8) + j] = a[7 - j];
				}

				//for(i=0;i<64;i++)
				//printf("%d,",text[i]);
				//printf("\n");

				//for(i=0;i<64;i++)
				//printf("%d,",text_out[l][i]);
				//printf("\n");

				for (i = 0; i < 64; i++) //CBC模式下前一分组的密文异或当前分组
					text[i] = text_out[l][i] ^ text[i];

				//for(i=0;i<64;i++)
				//printf("%d,",text[i]);
				//printf("\n");

				//对每个text进行DES加密

				for (i = 0; i < 64; i++) //进行初始换位
					text_ip[i] = text[IP[i] - 1];

				for (i = 0; i < 32; i++) //分成左右两部分,各32位
				{
					L0[i] = text_ip[i];
					R0[i] = text_ip[i + 32];
				}

				//for(i=0;i<32;i++)
				// printf("%d,",L0[i]);
				//for(i=0;i<32;i++)
				// printf("%d,",R0[i]);


				//十六次迭代

				for (t = 0; t < 16; t++)
				{
					for (i = 0; i < 48; i++) //将右半部分通过扩展换位表E从32位扩展成48位
						RE0[i] = R0[E[i] - 1];

					//printf("RE0\n");
					//for(i=0;i<48;i++)
					//printf("%d,",RE0[i]);

					for (i = 0; i < 48; i++) //RE与K异或运算
						RK[i] = RE0[i] ^ K[t][i];


					//printf("\n");
					//for(i=0;i<48;i++)
					//printf("%d,",RK[i]);

					for (i = 0; i < 8; i++) //将R和K异或运算的结果通过S位移表
					{
						r[i] = RK[(i * 6) + 0] * 2 + RK[(i * 6) + 5];
						c[i] = RK[(i * 6) + 1] * 8 + RK[(i * 6) + 2] * 4 + RK[(i * 6) + 3] * 2 + RK[(i * 6) + 4];
					}
					RKS[0] = S1[r[0]][c[0]];
					RKS[1] = S2[r[1]][c[1]];
					RKS[2] = S3[r[2]][c[2]];
					RKS[3] = S4[r[3]][c[3]];
					RKS[4] = S5[r[4]][c[4]];
					RKS[5] = S6[r[5]][c[5]];
					RKS[6] = S7[r[6]][c[6]];
					RKS[7] = S8[r[7]][c[7]];

					for (i = 0; i < 8; i++) //把结果转成32位二进制储存在数组SP中
					{
						int b[4] = { 0,0,0,0 };
						m = RKS[i];
						for (j = 3; m != 0; j--)
						{
							b[j] = m % 2;
							m = m / 2;
						}
						for (j = 0; j < 4; j++)
							SP[j + (i * 4)] = b[j];
					}

					for (i = 0; i < 32; i++) //将二进制结果再经过一个P盒换位
						RKSP[i] = SP[P[i] - 1];

					for (i = 0; i < 32; i++) //与前一次的左部异或运算,得到本次迭代的右部
						Ri[i] = L0[i] ^ RKSP[i];

					for (i = 0; i < 32; i++)
					{
						L0[i] = R0[i];
						R0[i] = Ri[i];
					}
				}

				//一个左右32位交换

				for (i = 0; i < 32; i++)
					Li[i] = R0[i];
				for (i = 0; i < 32; i++)
					R0[i] = L0[i];
				for (i = 0; i < 32; i++)
					L0[i] = Li[i];


				//初始换位的逆过程

				for (i = 0; i < 32; i++) //把左右两部分合起来存到text_end中
					text_end[i] = L0[i];
				for (i = 32; i < 64; i++)
					text_end[i] = R0[i - 32];

				for (i = 0; i < 64; i++) //进行初始换位的逆过程
					text_out[l + 1][IP[i] - 1] = text_end[i];

				for (i = 0; i < 64; i++)
					result[l][i] = text_out[l + 1][i];

				//for(i=0;i<64;i++)
				//printf("%d,",result[l][i]);
				//printf("\n");
			}

			for (j = 0; j < n; j++) //把result中的二进制密文转成十进制存到数组H中
				for (i = 0; i < 16; i++)
					H[i + (j * 16)] = result[j][0 + (i * 4)] * 8 + result[j][1 + (i * 4)] * 4 + result[j][2 + (i * 4)] * 2 + result[j][3 + (i * 4)];

			//for(i=0;i<l*16;i++)
			//printf("%d,",H[i]);

			for (i = 0; i < n * 16; i++)
			{
				if (H[i] < 10)
					MiWen[i] = H[i] + 48;
				else if (H[i] == 10)
					MiWen[i] = 'A';
				else if (H[i] == 11)
					MiWen[i] = 'B';
				else if (H[i] == 12)
					MiWen[i] = 'C';
				else if (H[i] == 13)
					MiWen[i] = 'D';
				else if (H[i] == 14)
					MiWen[i] = 'E';
				else if (H[i] == 15)
					MiWen[i] = 'F';
				//else MiWen[i]='\0';
			}
			for (i = l * 16; i < 208; i++)
				MiWen[i] = '\0';//注意数组越界

			printf("您的明文经过DES加密后的密文是:\n");
			printf("%s\n", MiWen);
			printf("\n\n");
		}


		//解密程序
		else if (choice == 'B' || choice == 'b')
		{
			printf("请输入密文内容:\n");
			gets_s(MiWen);

			for (i = 0; i < 208; i++)
				H[i] = 0;

			for (i = 0; MiWen[i] != '\0'; i++) //将十六进制密文转化成十进制存放在数组H中
			{
				if (MiWen[i] >= '0' && MiWen[i] <= '9')
					H[i] = MiWen[i] - '0';
				else if (MiWen[i] >= 'A' && MiWen[i] <= 'F')
					H[i] = MiWen[i] - 'A' + 10;
				else if (MiWen[i] >= 'a' && MiWen[i] <= 'f')
					H[i] = MiWen[i] - 'a' + 10;
				else
				{
					printf("注意:请输入用十六进制表示的密文内容:\n");
					gets_s(MiWen);
					i = 0;
				}
			}
			n = i; //密文中共有n个字符
			if (n % 16 != 0)
			{
				printf("对不起,您输入的密文不正确,请确认密文的内容,密文的字符数应是16的倍数。\n");
				printf("请输入密文内容:\n");
				gets_s(MiWen);

				for (i = 0; i < 208; i++)
					H[i] = 0;
				for (i = 0; MiWen[i] != '\0'; i++) //将十六进制密文转化成十进制存放在数组H中
				{
					if (MiWen[i] >= '0' && MiWen[i] <= '9')
						H[i] = MiWen[i] - '0';
					else if (MiWen[i] >= 'A' && MiWen[i] <= 'F')
						H[i] = MiWen[i] - 'A' + 10;
					else if (MiWen[i] >= 'a' && MiWen[i] <= 'f')
						H[i] = MiWen[i] - 'a' + 10;
				}
			}

			for (i = 0; i < n; i++) //将十进制密文转化成二进制存放在数组C中
			{
				int he[4] = { 0,0,0,0 };
				for (j = 3; H[i] != 0; j--)
				{
					he[j] = H[i] % 2;
					H[i] = H[i] / 2;
				}
				for (j = 0; j < 4; j++)
					C[j + (i * 4)] = he[j];
			}

			//for(i=0;i<130;i++)
			// printf("%d,",C[i]);
			//printf("\n");

			k = n / 16;
			for (l = 0; l < k; l++)
			{
				for (i = 0; i < 64; i++) //将每个分组对应的64位二进制密文放到text_out中
					text_out[l + 1][i] = C[i + (l * 64)];

				//for(i=0;i<64;i++)
				// printf("%d,",text_out[l][i]);
				//printf("\n");

				//对每个text进行DES解密

				for (i = 0; i < 64; i++) //进行初始换位
					text_ip[i] = text_out[l + 1][IP[i] - 1];

				//for(i=0;i<64;i++)
				//printf("%d,",text_ip[i]);
				//printf("\n");

				for (i = 0; i < 32; i++) //分成左右两部分,各32位
				{
					L0[i] = text_ip[i];
					R0[i] = text_ip[i + 32];
				}
				//for(i=0;i<32;i++)
				// printf("%d,",L0[i]);
				//for(i=0;i<32;i++)
				// printf("%d,",R0[i]);


				//十六次迭代

				for (t = 0; t < 16; t++)
				{
					for (i = 0; i < 48; i++) //将右半部分通过扩展换位表E从32位扩展成48位
						RE0[i] = R0[E[i] - 1];

					//printf("RE0\n");
					//for(i=0;i<48;i++)
					//printf("%d,",RE0[i]);

					for (i = 0; i < 48; i++) //RE与K异或运算
						RK[i] = RE0[i] ^ K[15 - t][i];

					//printf("\n");
					//for(i=0;i<48;i++)
					//printf("%d,",RK[i]);

					for (i = 0; i < 8; i++) //将R和K异或运算的结果通过S位移表
					{
						r[i] = RK[(i * 6) + 0] * 2 + RK[(i * 6) + 5];
						c[i] = RK[(i * 6) + 1] * 8 + RK[(i * 6) + 2] * 4 + RK[(i * 6) + 3] * 2 + RK[(i * 6) + 4];
					}

					RKS[0] = S1[r[0]][c[0]];
					RKS[1] = S2[r[1]][c[1]];
					RKS[2] = S3[r[2]][c[2]];
					RKS[3] = S4[r[3]][c[3]];
					RKS[4] = S5[r[4]][c[4]];
					RKS[5] = S6[r[5]][c[5]];
					RKS[6] = S7[r[6]][c[6]];
					RKS[7] = S8[r[7]][c[7]];

					for (i = 0; i < 8; i++) //把结果转成32位二进制储存在数组SP中
					{
						int b[4] = { 0,0,0,0 };
						m = RKS[i];
						for (j = 3; m != 0; j--)
						{
							b[j] = m % 2;
							m = m / 2;
						}
						for (j = 0; j < 4; j++)
							SP[j + (i * 4)] = b[j];
					}

					for (i = 0; i < 32; i++) //将二进制结果再经过一个P盒换位
						RKSP[i] = SP[P[i] - 1];

					for (i = 0; i < 32; i++) //与前一次的左部异或运算,得到本次迭代的右部
						Ri[i] = L0[i] ^ RKSP[i];

					for (i = 0; i < 32; i++)
					{
						L0[i] = R0[i];
						R0[i] = Ri[i];
					}
				}

				//一个左右32位交换

				for (i = 0; i < 32; i++)
					Li[i] = R0[i];
				for (i = 0; i < 32; i++)
					R0[i] = L0[i];
				for (i = 0; i < 32; i++)
					L0[i] = Li[i];

				//初始换位的逆过程

				for (i = 0; i < 32; i++) //把左右两部分合起来存到text_end中
					text_end[i] = L0[i];
				for (i = 32; i < 64; i++)
					text_end[i] = R0[i - 32];

				for (i = 0; i < 64; i++) //进行初始换位的逆过程 
					text[IP[i] - 1] = text_end[i];


				//CBC模式下的解密

				for (i = 0; i < 64; i++) //前一分组的密文异或当前分组所得明文的二进制放到result中
					result[l][i] = text_out[l][i] ^ text[i];

			}

			for (i = 0; i < (n / 16); i++) //将二进制转成十进制
				for (j = 0; j < 8; j++)
					M[i][j] = result[i][(j * 8) + 0] * 128 + result[i][(j * 8) + 1] * 64 + result[i][(j * 8) + 2] * 32 + result[i][(j * 8) + 3] * 16 + result[i][(j * 8) + 4] * 8 + result[i][(j * 8) + 5] * 4 + result[i][(j * 8) + 6] * 2 + result[i][(j * 8) + 7];

			printf("您的密文经过DES解密后的明文是:\n");
			for (i = 0; i < (n / 16); i++)
				for (j = 0; j < 8; j++)
					printf("%c", M[i][j]);
			printf("\n\n\n");
		}
		flag = 0;
		printf("是否继续?\n");
		printf("Y继续,N退出,请选择:\n");
		scanf("%c", &choice);

		while (choice != 'Y' && choice != 'N' && choice != 'y' && choice != 'n')
		{
			printf("对不起,您的输入不合法。请选择Y或N,Y表示继续使用本程序,N表示退出。\n");
			scanf("%c", &choice);
		}
		getchar();
		if (choice == 'Y' || choice == 'y')
			flag = 1;
	}
}

DES加密后解密中文乱码 des加密解密原理_迭代_13