您的位置:首页 > 编程语言 > C语言/C++

DES算法(C++实现)

2016-04-14 12:44 513 查看

DES算法(C++实现)

概述

DES算法的本质就是置换。通过多轮次多变化的置换将64bit的数据加密成密文,从而达到除了暴力破解(遍历密钥)之外没有其他(足够高效的)解法的目的。

DES算法的相关原理网上都有比较详尽的描述,理解起来并不困难,只是实现起来稍有点麻烦,一不小心就有可能出错。

在我的实现的过程中主要参考了网上的一篇 博客,实现之后的结果可以正常加密出结果,解密之后也可以得出原文,同时具有雪崩效应。

实验环境

系统:Windows 10 家庭中文版

IDE:Visual Studio 2015 Community

遇到的问题

实现DES算法之后可以正常加密出结果,解密之后也可以得出原文,同时具有雪崩效应,但是找了两份其他人的DES算法实现一对比,发现三份代码的加密结果都不一样(使用相同的key与加密原文)。。。所以必然有人的实现方法有问题。个人估计问题所在最有可能有以下几个方面:

对置换表的处理不同。例如置换表中第一个元素保存58,那么有人处理为原文第58位置换到此处,而有人处理为原文第1位置放到置换表的第58位。

S盒处的置换的逻辑有误。此处比较复杂,有可能出现失误,又因为加密解密的区别只是逆用密钥,所以也有可能出错了能够正常加密解密。

有人使用了非正统的置换表。按理说DES算法是公开公认的算法,所有人使用的置换表应该是相同的,才可以正常地解密。但是不排除有人使用了另一个不同却也可以对自己的加密数据进行加密解密的置换表的情况。

实验结果

由于时间精力有限,所以没有继续往下钻研,毕竟这次实验的目的只是理解DES加密算法的原理与实现,真正使用的时候大多情况下还是调用发展成熟完善的库函数的。这里就不给更多说明啦,下面丢代码,代码里加了大量中文注释便于理解与回忆。代码一共3个文件:

DES.h


DES.cpp


Main.cpp
(测试用例)

如果想直接要 VS Project 的话点击 这里 进行下载。

DES.h

#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.m

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


参考

DES加密解密(C++实现) - Canon of Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: