华南理工大学 软件学院
陈春华 (博士)
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 语言
编译环境。
四、 实验内容
路线一
- 分析和学习LibTomCrypt密码算法库,尤其是关于DES加解密算法的实现。
(见/libtomcrypt-1.17/doc/crypt.pdf)
路线二
-
使用一种编程语言(推荐用C或者C++,可使用其他语言,如JAVA等),实现DES加解密算法。
-
利用自己编程实现的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
输出两个密文块的二进制流,统计两个密文块间不同数据位的数量。
五、 实验报告要求
- 提交程序代码和执行结果(包括实验截图,和统计结果等)。
- 什么是雪崩效益?根据以上结果,说明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;
}