实验一 DES加密算法编程实现

华南理工大学 软件学院
陈春华 (博士)
chunhuachen@scut.edu.cn
一、 实验目的
通过使用DES 算法对实验数据进行加密和解密,掌握现代分组密码算法基本原理,熟练掌握DES 算法各部件的运算原理和具体运算过程。
二、 实验原理
现在密码算法可分为对称密码(Symmetric Cryptology)和非对称密码(Asymmetric Cryptology);其区分依据主要是所采用的密钥间的关系。在对称密码中,加密密钥和解密密钥是完全相同的,或彼此之间容易互相推导。在非对称密码算法,或称为公钥密码(Public Key Cryptology)中,加密密钥和解密密钥是不同的,从加密密钥推导出解密密钥在计算上是不可行的(Computationally infeasible)。
根据对明文的处理方式不同,密码算法又可分为流密码(Stream Cipher)和分组密码(Block Cipher)。一次只对明文中的单个比特(有时对字节)运算的密码称为流密码。对明文的一组比特进行运算,这些比特组称为分组(如64位比特为一组),相应的密码称为分组密码。
1973 年,美国国家标准局(NBS)开始征集一种标准的数据加密标准算法(DES),以用于非机密性政府机构、商业部门和民间的对非机密的敏感数据进行加密。IBM 公司在1971年完成的LUCIFER 密码(64 比特分组,128 比特密钥)的基础上,改进成为建议的DES。改进后的DES算法仅使用56比特密钥,同时对S盒的修改被列入官方机密,曾广受批评。1975 年3 月17 日,NBS 公布了这个算法,并说明要以它作为联邦信息处理标准,征求各方意见。1977 年1 月15 日,建议被批准为联邦标准—FIPSPUB 46,并设计推出了DES 芯片。1981 年,ANSI 将DES 作为标准,即DEA[ANSI X3.92]。1983 年,ISO 采用DES 作为标准,即DEA-1。DES(Data Encryption Standard)是一个优秀的对称分组密码算法,直到2000 年10 月2 日NIST 宣布AES 算法前,其一直是业界的标准。
三、 实验环境
运行Windows 或Linux 操作系统的PC 机,具有gcc(Linux)、VC(Windows)等C 语言
编译环境。

四、 实验内容
路线一

  1. 分析和学习LibTomCrypt密码算法库,尤其是关于DES加解密算法的实现。
    (见/libtomcrypt-1.17/doc/crypt.pdf)

路线二

  1. 使用一种编程语言(推荐用C或者C++,可使用其他语言,如JAVA等),实现DES加解密算法。

  2. 利用自己编程实现的DES算法或者LibTomCryp库提供的DES算法,进行如下加密和解密操作。
    a) 使用同一密钥,对两组明文进行加密和解密。
    64位密钥:
    00000010 10010110 01001000 11000100 00111000 00110000 00111000 01100100

64位明文块1:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

64位明文块2(与明文块1仅有一位的不同):
10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

输出两个密文块的二进制流,统计两个密文块间不同数据位的数量。

b) 对同一段明文,使用不同密钥进行加密和解密操作。
64位密钥1:
11100010 11110110 11011110 00110000 00111010 00001000 01100010 11011100

64位密钥2(与密钥1仅有一位的不同):
01100010 11110110 11011110 00110000 00111010 00001000 01100010 11011100

明文:
01101000 10000101 00101111 01111010 00010011 01110110 11101011 10100100

输出两个密文块的二进制流,统计两个密文块间不同数据位的数量。

五、 实验报告要求

  1. 提交程序代码和执行结果(包括实验截图,和统计结果等)。
  2. 什么是雪崩效益?根据以上结果,说明DES加密算法是否具有该性质。

DES.h

#pragma once
#define BIT bool

class DES {
public:
	static void des_encrypt(BIT input[64], BIT output[64], BIT key[64]);
	static void des_decrypt(BIT input[64], BIT output[64], BIT key[64]);
};

DES.cpp

#include <iostream>
#include "DES.h"
using namespace std;

#define BIT bool

BIT keys[16][48];

// 函数声明
static void permute(BIT *input, BIT *output, int *box, int length);
static void inital_permute(BIT *input, BIT *output);
static void final_permute(BIT *input, BIT *output);
static void generate_keys(BIT key[64]);
static void encrypt_every_turn(BIT left_data[32], BIT right_data[32], BIT key[48], int turn);
static void encrypt_or_decrypt(BIT input[64], BIT output[64], BIT key[64], bool isEncrypt);

// 加密
void DES::des_encrypt(BIT input[64], BIT output[64], BIT key[64]) {
	encrypt_or_decrypt(input, output, key, true);
}

// 解密
void DES::des_decrypt(BIT input[64], BIT output[64], BIT key[64]) {
	encrypt_or_decrypt(input, output, key, false);
}

// 封装好的置换函数
void permute(BIT *input, BIT *output, int *box, int length) {
	for (int i = 0; i < length; ++i) {
		output[i] = input[box[i] - 1];
	}
}

// 初始置换
void inital_permute(BIT *input, BIT *output) {
	static 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 };
	permute(input, output, IP, 64);
}

// 最终置换
void final_permute(BIT *input, BIT *output) {
	static int FP[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 };
	permute(input, output, FP, 64);
}

// 生成加密密钥
void generate_keys(BIT key[64]) {
	// KP:密钥置换选择1(64->56)
	static int KP[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 };

	// KM:每轮生成密钥的位移
	static int KM[16] = {
		1 ,  1 ,  2 ,  2 ,  2 ,  2 ,  2 ,  2 ,
		1 ,  2 ,  2 ,  2 ,  2 ,  2 ,  2 ,  1 };

	// CP:密钥置换选择2(56->48)
	static int CP[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 };

	BIT L[60], R[60];

	// 1. 密钥置换选择1(64->56)
	for (int i = 0; i < 28; ++i) {
		L[i + 28] = L[i] = key[KP[i] - 1],
			R[i + 28] = R[i] = key[KP[i + 28] - 1];
	}

	// 2. 密钥位移、置换选择2(56->48)
	int shift = 0; // 密钥位移量
	for (int i = 0; i < 16; ++i) {
		shift += KM[i];
		for (int j = 0; j < 48; ++j) {
			if (CP[j] < 28)
				keys[i][j] = L[CP[j] + shift - 1];
			else
				keys[i][j] = R[CP[j] - 28 + shift - 1];
		}
	}
}

// 每个轮次的加密
void encrypt_every_turn(BIT left_data[32], BIT right_data[32], BIT key[48], int turn) {
	// 扩展置换
	static int EP[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 };

	// S盒
	static 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 } } };

	// P盒
	static int PP[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 };

	BIT tmp_48[48];
	BIT tmp_32[32];
	memset(tmp_32, 0, sizeof(tmp_32));

	// 1. 扩展置换(32->48)、与本轮次的密钥异或
	for (int i = 0; i < 48; ++i)
		tmp_48[i] = right_data[EP[i] - 1] ^ key[i];

	// 2. S盒代换选择(48->32)
	int count_of_box = 8;
	for (int i = 0; i < count_of_box; ++i) {
		int index_of_input = i * 6;
		int row_in_box = (tmp_48[index_of_input] << 1) + tmp_48[index_of_input + 5];
		int column_in_box = (tmp_48[index_of_input + 1] << 3) +
			(tmp_48[index_of_input + 2] << 2) +
			(tmp_48[index_of_input + 3] << 1) +
			(tmp_48[index_of_input + 4]);
		int temp_var = S_box[i][row_in_box][column_in_box];

		int index_of_output = i * 4;
		for (int j = 0; j < 4; ++j)
			tmp_32[index_of_output + (3 - j)] |= (temp_var >> j) & 1;
	}

	// 3. P盒置换
	BIT tmp_32_2[32];
	permute(tmp_32, tmp_32_2, PP, 32);

	// 4. 异或
	for (int i = 0; i < 32; ++i)
		left_data[i] ^= tmp_32_2[i];

	// 5. 如果未到最终轮则交换left_data与right_data
	if (turn != 15) {
		memcpy(tmp_32, left_data, 32);
		memcpy(left_data, right_data, 32);
		memcpy(right_data, tmp_32, 32);
	}
}

// 加密/解密函数(算法相同,只是轮密钥的使用次序相反)
void encrypt_or_decrypt(BIT input[64], BIT output[64], BIT key[64], bool isEncrypt) {
	// 初始置换
	BIT tmp[64];
	inital_permute(input, tmp);

	// 将64位数据分成两部分
	BIT left_data[32], right_data[32];
	for (int i = 0; i < 32; ++i) {
		left_data[i] = tmp[i];
		right_data[i] = tmp[i + 32];
	}

	// 生成轮密钥
	generate_keys(key);

	// 进行16轮加密/解密
	if (isEncrypt) {
		for (int i = 0; i < 16; ++i)
			encrypt_every_turn(left_data, right_data, keys[i], i);
	}
	else {
		for (int i = 0; i < 16; ++i)
			encrypt_every_turn(left_data, right_data, keys[15 - i], i);
	}

	// 将两部分数据重新组合成64位数据
	for (int i = 0; i < 32; ++i) {
		tmp[i] = left_data[i];
		tmp[i + 32] = right_data[i];
	}

	// 最终置换
	final_permute(tmp, output);
}

main.cpp

#include <iostream>
#include <string>
#include "DES.h"
using namespace std;

#define BIT bool

void strToBit(string str, BIT bit[64]) {
	int count = 0, index_of_str = 0;
	while (true) {
		if (64 == count)
			break;
		if (' ' == str[index_of_str]) {
			++index_of_str;
			continue;
		}
		bit[count] = bool(str[index_of_str] - '0');
		++count;
		++index_of_str;
	}
}

string bitToStr(BIT bit[64]) {
	string str = "";
	for (int i = 0; i < 8; ++i) {
		for (int j = 0; j < 8; ++j)
			str.insert(str.end(), bit[i * 8 + j] + '0');
		str.insert(str.end(), ' ');
	}
	return str;
}

// 测试用例(1):使用同一密钥,对两组明文进行加密和解密
void test1() {
	string keyStr;
	BIT    keyBit[64];

	string inputStr;
	BIT    inputBit[64];
	string encryptStr;
	BIT    encryptBit[64];
	string decryptStr;
	BIT    decryptBit[64];

	string inputStr2;
	BIT    inputBit2[64];
	string encryptStr2;
	BIT    encryptBit2[64];
	string decryptStr2;
	BIT    decryptBit2[64];

	cout << "====================================================\n测试用例(1):使用同一密钥,对两组明文进行加密和解密\n\n";

	keyStr = "00000010 10010110 01001000 11000100 00111000 00110000 00111000 01100100";
	inputStr = "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000";
	inputStr2 = "10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000";
	strToBit(keyStr, keyBit);
	strToBit(inputStr, inputBit);
	strToBit(inputStr2, inputBit2);

	DES::des_encrypt(inputBit, encryptBit, keyBit);
	DES::des_decrypt(encryptBit, decryptBit, keyBit);
	encryptStr = bitToStr(encryptBit);
	decryptStr = bitToStr(decryptBit);

	DES::des_encrypt(inputBit2, encryptBit2, keyBit);
	DES::des_decrypt(encryptBit2, decryptBit2, keyBit);
	encryptStr2 = bitToStr(encryptBit2);
	decryptStr2 = bitToStr(decryptBit2);

	int diff = 0;
	for (int i = 0; i < 64; ++i) {
		if (encryptBit[i] == encryptBit2[i])
			++diff;
	}

	cout << "Key      : " << keyStr << "\n\n";

	cout << "Input1   : " << inputStr
		<< "\nEncrypt1 : " << encryptStr
		<< "\nDecrypt1 : " << decryptStr << "\n\n";

	cout << "Input2   : " << inputStr2
		<< "\nEncrypt2 : " << encryptStr2
		<< "\nDecrypt2 : " << decryptStr2 << "\n\n";

	cout << "Number of different digits: " << diff << "\n\n";

}

// 测试用例(2):对同一段明文,使用不同密钥进行加密和解密操作
void test2() {
	string inputStr;
	BIT    inputBit[64];

	string keyStr;
	BIT    keyBit[64];
	string encryptStr;
	BIT    encryptBit[64];
	string decryptStr;
	BIT    decryptBit[64];

	string keyStr2;
	BIT    keyBit2[64];
	string encryptStr2;
	BIT    encryptBit2[64];
	string decryptStr2;
	BIT    decryptBit2[64];

	cout << "====================================================\n测试用例(2):对同一段明文,使用不同密钥进行加密和解密操作\n\n";

	inputStr = "01101000 10000101 00101111 01111010 00010011 01110110 11101011 10100100";
	keyStr = "11100010 11110110 11011110 00110000 00111010 00001000 01100010 11011100";
	keyStr2 = "01100010 11110110 11011110 00110000 00111010 00001000 01100010 11011100";
	strToBit(inputStr, inputBit);
	strToBit(keyStr, keyBit);
	strToBit(keyStr2, keyBit2);

	DES::des_encrypt(inputBit, encryptBit, keyBit);
	DES::des_decrypt(encryptBit, decryptBit, keyBit);
	encryptStr = bitToStr(encryptBit);
	decryptStr = bitToStr(decryptBit);

	DES::des_encrypt(inputBit, encryptBit2, keyBit2);
	DES::des_decrypt(encryptBit2, decryptBit2, keyBit2);
	encryptStr2 = bitToStr(encryptBit2);
	decryptStr2 = bitToStr(decryptBit2);

	int diff = 0;
	for (int i = 0; i < 64; ++i) {
		if (encryptBit[i] == encryptBit2[i])
			++diff;
	}

	cout << "Input    : " << inputStr << "\n\n";

	cout << "Key1     : " << keyStr
		<< "\nEncrypt1 : " << encryptStr
		<< "\nDecrypt1 : " << decryptStr << "\n\n";

	cout << "Key2     : " << keyStr2
		<< "\nEncrypt2 : " << encryptStr2
		<< "\nDecrypt2 : " << decryptStr2 << "\n\n";

	cout << "Number of different digits: " << diff << "\n\n";
}

int main() {
	test1();
	test2();

	system("pause");
	return 0;
}
  • 12
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值