密码学:DES加解密算法的C语言实现(64bit字符串加解密版本)

本文详细介绍DES算法的具体实现过程,包括核心代码与测试流程,适用于理解并实现DES加密解密算法。

版权声明:本文为博主原创文章,若是用于商业用途只需要注明出处即可。

  本文主要讲述DES算法的具体实现过程,不再重复说明DES的原理了。
到最后会完成结果如下:

输入string:ilovedes
输入key:1234abcd
显示输入序列(2进制):01101001 01101100 01101111 01110110 01100101 01100100 01100101 01110011
显示加密序列(2进制):10001001 10111110 00101001 11111001 00111010 01101000 10110111 00101010
显示解密序列(2进制):01101001 01101100 01101111 01110110 01100101 01100100 01100101 01110011

  如果 输入序列 等于 解密序列 则加解密成功。
[注意] 二进制的序列比较可以直观看出加解密的结果,也可以转化为char*类型,文末提供额外函数以供参考。

一、大概过程

  DES加解密的大概过程如下:

     (1)IP置换
     (2)16轮Feistel运算
     (3)64bit数据前32位和后32位互换
     (4)逆IP置换

  输入64bit数据,经过上述过程,处理得到的密文64bit。

二、准备表

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 };

2.扩展置换表–E

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 };

3.S盒(共8个)

int S_BOX[8][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
	},
	{	
		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
	}
};

4.P置换表

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 };

5.PC_1表

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 };

6.PC_2表

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 };

7.移位次数关系表–M

int M_Table[16] = {
	1,1,2,2,
	2,2,2,2,
	1,2,2,2,
	2,2,2,1
};

8.逆初始置换表–IP_N

int IP_N_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 };

三、核心代码

   按照实现的步骤进行即可。

1、设置头文件等

   如果含有全局变量,全局变量都会在后面的步骤中说明,是为了用于可以随时debug相关信息,可以用于C++类的组成。如果不需要,可以在main()函数中另外定义变量存储。相关调试函数不会对程序稳定造成影响!

#include<iostream>
using namespace std;

2、扩展KEY

   在进行正式的加密运算之前,我们先来生成KEY数组。
  (注意:在之后的步骤中,小写key代表< 密钥字符串转化成的bool [64bit] >,大写KEY代表< 扩展的密钥数组bool [16][48] >)

(1)PC_1置换

   输入64bit密钥,输出28bit和28bit 。

void PC_1(bool key[64],bool l[28],bool r[28]) {
	for (int i = 0; i < 28; i++) {
		l[i] = key[PC1_TABLE[i] - 1];//PC1_TABLE[i]是从1开始的位置,在数组中坐标需要减1(数组从0开始)
		r[i] = key[PC1_TABLE[i+28] - 1];
	}
}

(2)循环左移

   输入input (bool数组)、 bitArrayLen (数组长度)、moveNum (左移距离)。输出 output(bool数组)。

void MoveLeft(bool *input,bool *output,int bitArrayLen,int moveNum) {
	for (int i = 0; i < bitArrayLen; i++)
		output[i] = input[(i + moveNum) % bitArrayLen];
}

(3)PC_2置换

   输入28bit和28bit,输出48bit子密钥 。

void PC_2(bool l[28],bool r[28],bool key[48]){
	bool temp[56] = { 0 };
	int i = 0;
	//合并成56bit
	for (i = 0; i < 28; i++) {
		temp[i] = l[i];
		temp[i + 28] = r[i];
	}
	//压缩成key
	for (int i = 0; i < 48; i++)
		key[i] = temp[PC2_TABLE[i] - 1];
}

(4)生成密钥数组

   每轮子密钥获取。输入l[28],r[28],当前轮数round 。输出子密钥c_key。(c_key命名由来:child_key)

void getKeyRound(bool L[28], bool R[28], bool c_key[48], int round) {
	//l与r是函数内操作的32bit,可以看做缓存
	bool l[28] = { 0 };
	bool r[28] = { 0 };
	int moveNum = M_Table[round];//左移位数
	//循环左移
	MoveLeft(R, r, 28, moveNum);
	MoveLeft(L, l, 28, moveNum);
	//PC2置换
	PC_2(l,r, c_key);
	//L与R替换成循环左移后的数据
	for (int i = 0; i < 28; i++) {
		R[i] = r[i];
		L[i] = l[i];
	}
}

   生成密钥数组。输入key[64],输出KEY[16][48] 。(均为bool数组)

void getKey(bool key[64], bool KEY[16][48]) {
	bool L[28] = { 0 };
	bool R[28] = { 0 };
	PC_1(key, L, R);//置换	PC-1
	for (int i = 0; i < 16; i++) {
		getKeyRound(L, R,  KEY[i],i);//每轮获取子密钥
	}
}

3、加密部分

(1)初始IP置换

   输入64bit,输出64bit

void IP(bool input[64],bool output[64]) {
	for (int i = 0; i < 64; i++)
		output[i] = input[IP_TABLE[i] - 1];
}

(2)Feistel运算

  初始置换后会将64bit数据分为L与R(各32bit)。
  以下是每轮的Feistel运算,总共16轮。

   第1步,R与子密钥c_key通过F()输出r。
   第2步,L与r异或输出l。
   第3步,L=R,R=l。

  1)先完成F函数。
  F函数使用了E函数、XOR函数(异或)、S盒置换、P函数。

  代码(E函数):

void E(bool R[32], bool output[48]) {
	for (int i = 0; i < 48; i++)
		output[i] = R[E_TABLE[i] - 1];
}

  代码(XOR函数):

void XOR(bool *input1,bool *input2,bool*output,int len) {
	for (int i = 0; i < len; i++)
		output[i] = input1[i] ^ input2[i];
}

  代码(S函数)以及相关工具函数:(工具函数是为了代码的可阅读性。)

int Mi(int num, int n) {//返回num的n次幂
	if (n <= 0)
		return 1;
	else
		return Mi(num, n - 1)*num;
}
int BitToInt(bool *bit, int bitArrayLen) {//输入2进制数组,返回整数
	int num = 0;
	int i = bitArrayLen - 1;
	while (i >= 0) {
		if (bit[i] == 1) {
			num += Mi(2, bitArrayLen - 1 - i);
		}
		i--;
	}
	return num;
}
void IntToBit4(int num, bool bit[4]) {//整数转化为4bit大小的bool数组
	int i = 3;
	while (num != 0 && i >= 0) {
		if (num % 2 == 1)
			bit[i--] = 1;
		else
			bit[i--] = 0;
		num /= 2;
	}
	while (i >= 0) {
		bit[i--] = 0;
	}
}
void S(bool input[48], bool output[32]) {//输入48bit,输出32bit
	int i = 0;
	int j = 0;
	int t = 0;

	for (i = 0; i < 8; i++) {//8个S盒,每个盒子输入6bit,输出4bit
		//t是每次输入的起始坐标
		t = 6 * i;
		//每个循环内单独定义,为了不必重新初始化。
		bool line[2] = { input[t],input[t + 5] };
		bool row[4] = { input[t + 1] ,input[t + 2] ,input[t + 3] ,input[t + 4] };
		int num = S_BOX[i][BitToInt(line, 2)][BitToInt(row, 4)];
		bool bit4[4] = { 0 };
		IntToBit4(num, bit4);
		for (j = 0; j < 4; j++)//将输出的4bit数据复制到output的对应位置
			output[4 * i + j] = bit4[j];
	}
}

  代码(P函数):

void P(bool input[32], bool output[32]) {
	for (int i = 0; i < 32; i++)
		output[i] = input[P_TABLE[i] - 1];
}

  代码(F函数):

void F(bool input[32], bool key[48], bool output[32]) {
	bool e48[48] = { 0 };//缓存
	E(input, e48);

	bool xor48[48] = { 0 };//缓存
	XOR(e48, key, xor48, 48);

	bool s32[32] = { 0 };//缓存
	S(xor48, s32);

	P(s32, output);
}

  2)单轮Feistel运算。

void FeistelRound(bool L[32], bool R[32], bool c_key[48]) {//输入L,R,c_key
	bool f32[48] = { 0 };
	bool r[32] = { 0 };//函数内的缓存
	bool l[32] = { 0 };//函数内的缓存
	int i = 0;
	//r保存R的数据
	for (i = 0; i < 32; i++) {
		r[i] = R[i];
	}

	F(R, c_key, f32);
	//使用l保存L与f32异或后的数据
	XOR(f32, L, l, 32);

	//当前轮次运算完毕,交换L与R的值
	for (int i = 0; i < 32; i++) {
		L[i] = r[i];
		R[i] = l[i];
	}
}

  3)Feistel运算。

void Feistel(bool input[64],bool output[64],bool KEY[16][48],bool ifEnCrypt) {
	bool L[32] = { 0 };
	bool R[32] = { 0 };
	int i = 0;
	//L、R赋值
	for (i = 0; i < 32;i++) {
		L[i] = input[i];
		R[i] = input[i + 32];
	}
	for (i = 0; i < 16; i++) {
		if (ifEnCrypt == true)//加密
			FeistelRound(L, R, KEY[i]);
		else//解密
			FeistelRound(L, R, KEY[15-i]);//i的范围0-15
	}
	for (i = 0; i < 32; i++) {//最后交换L、R
		output[i] = R[i];
		output[ i + 32 ] = L[i];
	}
}

(3)逆IP置换

void IP_N(bool input[64], bool output[64]) {
	for (int i = 0; i < 64; i++)
		output[i] = input[IP_N_Table[i] - 1];
}

(4)加解密模块

加密

void EnCrypt(bool input[64],bool KEY[16][48],bool output[64]) {
	bool b64[64] = { 0 };
	IP(input, b64);

	bool o64[64] = { 0 };
	Feistel( b64, o64, KEY, true);
	
	IP_N(o64, output);
}

解密。

void DeCrypt(bool input[64], bool KEY[16][48], bool output[64]) {
	bool b64[64] = { 0 };
	IP(input, b64);

	bool o64[64] = { 0 };
	Feistel(b64, o64, KEY, false);

	IP_N(o64, output);
}

4、测试

  在前面我们已经完成了DES的核心加密功能了。为了能够方便以后扩展其他功能,如:文件加密、长字符串加密、分组密码工作模式、3DES等,可以扩写其他函数。
  扩写其他函数的标准:函数功能尽量支持重复使用、命名可读性、命名合理性等。

(1)字符串与bool数组之间的转换

  为什么本程序多使用bool数组?
  我认为,bool类型只有1或0,比较贴合比特的属性,也节省了一些内存空间。
  因为输入是char * 类型的,如果直接在程序中转换,会造成代码难以阅读,因此另外编写函数来输出以及转换。

1)一个字节转为8个bit

void CharToBit(char input,bool output[8]) {//1个字符转为8bit
	int i = 7;
	if(input==0){//如果输入为空,则bit数组置0
        for(i=0;i<8;i++){
            output[i]=0;
        }
    }
	while (input != 0 && i >= 0) {
		if (input % 2 == 1)
			output[i--] = 1;
		else
			output[i--] = 0;
		input /= 2;
	}
	while (i >= 0) {
		output[i--] = 0;
	}
}

2)n个字节转为8n个bit

void CharToBit(char *input, bool *output,int n) {//n个字符转为8n个bit
	for (int j = 0; j < n; j++)
		CharToBit(input[j], output + j * 8);
}

(2)显示bit序列

打印长度为n的bool数组

void PrintBit(bool *bit,int n) {
	for (int i = 0; i < n; i++) {
		if ((i + 1) % 8 == 0)//每8个bit空一格输出,方便观察
			cout << bit[i] << " ";
		else
			cout << bit[i];
	}
	cout << endl;
}

(3)在main函数中进行测试

void main() {
	char str[10] = { 0 };
	char str_key[10] = { 0 };

	bool b_key[64] = { 0 };
	bool b_KEY[16][48] = { 0 };
	bool b_str[64] = { 0 };
	bool b_encrypt[64] = { 0 };
	bool b_decrypt[64] = { 0 };

	cout << "输入string:"; cin >> str;
	cout << "输入key:"; cin>>str_key; 

	CharToBit(str, b_str, 8);//str转化为b_str
	CharToBit(str_key, b_key, 8);//str_key转化为b_key
	getKey(b_key,b_KEY);//b_key转化为b_KEY
	
	EnCrypt(b_str,b_KEY,b_encrypt);//加密
	DeCrypt(b_encrypt, b_KEY, b_decrypt);//解密
	
	cout << "显示输入序列(2进制):"; PrintBit(b_str, 64);
	cout << "显示加密序列(2进制):"; PrintBit(b_encrypt, 64);
	cout << "显示解密序列(2进制):"; PrintBit(b_decrypt, 64);
	
	system("pause");
}

(4)测试结果

实验结果

四、一些总结

  (1)DES算法算是比较简单的一个算法了,逻辑部分很好实现,按照教程手敲过一遍基本会熟悉它的过程了。
  (2)我的编程思想是:先把函数做好,再在主函数里实现逻辑就很方便了,想用某个功能时候立马就能想起就是这个函数。
  (3)为什么输出对比时用的是二进制序列而不是字符串?我此处用的是char类型的,char范围-128到127。当bit数组为1000 0000时候转化为char时候会返回残缺数据,感兴趣的可以用BitToChar()函数单独尝试下。而且转化为字符数组显示并不能看出加密后的数据变化。
   解决办法: 使用unsigned char或unsigned char * ;(本文没有使用因为只是为了加密比特,而不是需要输出。读者可以自行另外写函数输出。)

附件(完整代码)

#include<iostream>
using namespace std;
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] = {                                    //扩展矩阵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 };
int S_BOX[8][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
	}
};

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 PC1_TABLE[56] = {                           // PC_1    
	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] = {                          // PC_2  
	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 M_Table[16] = {
	1,1,2,2,
	2,2,2,2,
	1,2,2,2,
	2,2,2,1
};
int IP_N_Table[64] = {                                   //逆初始置换矩阵IP_N  
	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 };

void PC_1(bool key[64], bool l[28], bool r[28]) {
	for (int i = 0; i < 28; i++) {
		l[i] = key[PC1_TABLE[i] - 1];//PC1_TABLE[i]是从1开始的位置,在数组中坐标需要减1(数组从0开始)
		r[i] = key[PC1_TABLE[i + 28] - 1];
	}
}
void MoveLeft(bool *input, bool *output, int bitArrayLen, int moveNum) {
	for (int i = 0; i < bitArrayLen; i++)
		output[i] = input[(i + moveNum) % bitArrayLen];
}
void PC_2(bool l[28], bool r[28], bool key[48]) {
	bool temp[56] = { 0 };
	int i = 0;
	//合并成56bit
	for (i = 0; i < 28; i++) {
		temp[i] = l[i];
		temp[i + 28] = r[i];
	}
	//压缩成key
	for (int i = 0; i < 48; i++)
		key[i] = temp[PC2_TABLE[i] - 1];
}
void getKeyRound(bool L[28], bool R[28], bool c_key[48], int round) {
	//l与r是函数内操作的32bit,可以看做缓存
	bool l[28] = { 0 };
	bool r[28] = { 0 };
	int moveNum = M_Table[round];//左移位数
								 //循环左移
	MoveLeft(R, r, 28, moveNum);
	MoveLeft(L, l, 28, moveNum);
	//PC2置换
	PC_2(l, r, c_key);
	//L与R替换成循环左移后的数据
	for (int i = 0; i < 28; i++) {
		R[i] = r[i];
		L[i] = l[i];
	}
}
void getKey(bool key[64], bool KEY[16][48]) {
	bool L[28] = { 0 };
	bool R[28] = { 0 };
	PC_1(key, L, R);//置换	PC-1
	for (int i = 0; i < 16; i++) {
		getKeyRound(L, R, KEY[i], i);//每轮获取子密钥
	}
}
void IP(bool input[64], bool output[64]) {
	for (int i = 0; i < 64; i++)
		output[i] = input[IP_TABLE[i] - 1];
}
void E(bool R[32], bool output[48]) {
	for (int i = 0; i < 48; i++)
		output[i] = R[E_TABLE[i] - 1];
}
void XOR(bool *input1, bool *input2, bool*output, int len) {
	for (int i = 0; i < len; i++)
		output[i] = input1[i] ^ input2[i];
}
int Mi(int num, int n) {//返回num的n次幂
	if (n <= 0)
		return 1;
	else
		return Mi(num, n - 1)*num;
}
int BitToInt(bool *bit, int bitArrayLen) {//输入2进制数组,返回整数
	int num = 0;
	int i = bitArrayLen - 1;
	while (i >= 0) {
		if (bit[i] == 1) {
			num += Mi(2, bitArrayLen - 1 - i);
		}
		i--;
	}
	return num;
}
void IntToBit4(int num, bool bit[4]) {//整数转化为4bit大小的bool数组
	int i = 3;
	while (num != 0 && i >= 0) {
		if (num % 2 == 1)
			bit[i--] = 1;
		else
			bit[i--] = 0;
		num /= 2;
	}
	while (i >= 0) {
		bit[i--] = 0;
	}
}
void S(bool input[48], bool output[32]) {//输入48bit,输出32bit
	int i = 0;
	int j = 0;
	int t = 0;

	for (i = 0; i < 8; i++) {//8个S盒,每个盒子输入6bit,输出4bit
							 //t是每次输入的起始坐标
		t = 6 * i;
		//每个循环内单独定义,为了不必重新初始化。
		bool line[2] = { input[t],input[t + 5] };
		bool row[4] = { input[t + 1] ,input[t + 2] ,input[t + 3] ,input[t + 4] };
		int num = S_BOX[i][BitToInt(line, 2)][BitToInt(row, 4)];
		bool bit4[4] = { 0 };
		IntToBit4(num, bit4);
		for (j = 0; j < 4; j++)//将输出的4bit数据复制到output的对应位置
			output[4 * i + j] = bit4[j];
	}
}

void P(bool input[32], bool output[32]) {
	for (int i = 0; i < 32; i++)
		output[i] = input[P_TABLE[i] - 1];
}
void F(bool input[32], bool key[48], bool output[32]) {
	bool e48[48] = { 0 };//缓存
	E(input, e48);

	bool xor48[48] = { 0 };//缓存
	XOR(e48, key, xor48, 48);

	bool s32[32] = { 0 };//缓存
	S(xor48, s32);

	P(s32, output);
}
void FeistelRound(bool L[32], bool R[32], bool c_key[48]) {//输入L,R,c_key
	bool f32[48] = { 0 };
	bool r[32] = { 0 };//函数内的缓存
	bool l[32] = { 0 };//函数内的缓存
	int i = 0;
	//r保存R的数据
	for (i = 0; i < 32; i++) {
		r[i] = R[i];
	}

	F(R, c_key, f32);
	//使用l保存L与f32异或后的数据
	XOR(f32, L, l, 32);

	//当前轮次运算完毕,交换L与R的值
	for (int i = 0; i < 32; i++) {
		L[i] = r[i];
		R[i] = l[i];
	}
}
void Feistel(bool input[64], bool output[64], bool KEY[16][48], bool ifEnCrypt) {
	bool L[32] = { 0 };
	bool R[32] = { 0 };
	int i = 0;
	//L、R赋值
	for (i = 0; i < 32; i++) {
		L[i] = input[i];
		R[i] = input[i + 32];
	}
	for (i = 0; i < 16; i++) {
		if (ifEnCrypt == true)//加密
			FeistelRound(L, R, KEY[i]);
		else//解密
			FeistelRound(L, R, KEY[15 - i]);//i的范围0-15
	}
	for (i = 0; i < 32; i++) {//最后交换L、R
		output[i] = R[i];
		output[i + 32] = L[i];
	}
}
void IP_N(bool input[64], bool output[64]) {
	for (int i = 0; i < 64; i++)
		output[i] = input[IP_N_Table[i] - 1];
}

void EnCrypt(bool input[64], bool KEY[16][48], bool output[64]) {
	bool b64[64] = { 0 };
	IP(input, b64);

	bool o64[64] = { 0 };
	Feistel(b64, o64, KEY, true);

	IP_N(o64, output);
}
void DeCrypt(bool input[64], bool KEY[16][48], bool output[64]) {
	bool b64[64] = { 0 };
	IP(input, b64);

	bool o64[64] = { 0 };
	Feistel(b64, o64, KEY, false);

	IP_N(o64, output);
}
void CharToBit(char input, bool output[8]) {//1个字符转为8bit
	int i = 7;
	if(input==0){//如果输入为空,则bit数组置0
        for(i=0;i<8;i++){
            output[i]=0;
        }
    }
	while (input != 0 && i >= 0) {
		if (input % 2 == 1)
			output[i--] = 1;
		else
			output[i--] = 0;
		input /= 2;
	}
	while (i >= 0) {
		output[i--] = 0;
	}
}
void CharToBit(char *input, bool *output, int n) {//n个字符转为8n个bit
	for (int j = 0; j < n; j++)
		CharToBit(input[j], output + j * 8);
}
void PrintBit(bool *bit, int n) {
	for (int i = 0; i < n; i++) {
		if ((i + 1) % 8 == 0)//每8个bit空一格输出,方便观察
			cout << bit[i] << " ";
		else
			cout << bit[i];
	}
	cout << endl;
}
void main() {
	char str[10] = { 0 };
	char str_key[10] = { 0 };

	bool b_key[64] = { 0 };
	bool b_KEY[16][48] = { 0 };
	bool b_str[64] = { 0 };
	bool b_encrypt[64] = { 0 };
	bool b_decrypt[64] = { 0 };

	cout << "输入string:"; cin >> str;
	cout << "输入key:"; cin >> str_key;

	CharToBit(str, b_str, 8);//str转化为b_str
	CharToBit(str_key, b_key, 8);//str_key转化为b_key
	getKey(b_key, b_KEY);//b_key转化为b_KEY

	EnCrypt(b_str, b_KEY, b_encrypt);//加密
	DeCrypt(b_encrypt, b_KEY, b_decrypt);//解密

	cout << "显示输入序列(2进制):"; PrintBit(b_str, 64);
	cout << "显示加密序列(2进制):"; PrintBit(b_encrypt, 64);
	cout << "显示解密序列(2进制):"; PrintBit(b_decrypt, 64);

	system("pause");
}

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值