二、实验项目内容
1.编写DES子密钥的生成算法,并根据自己设定的种子密钥运行程序产生并显示出16轮的子密钥,同时完成DES算法弱秘钥和半弱秘钥对的验证;
2.应用DES算法程序实现对一个文件进行加密和解密,提交程序代码和执行结果。
3.用DES算法对输入的十六进制数加密,比较输入和输出,当改变一个位时比较输出的变化,并说明原因。
三、实验过程或算法(源程序)
以下程序的运行环境都是window10 + CLion, 编程语言为c++。
1.
#include <iostream>
#include<string>
using namespace std;
int PC1[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 PC2[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 lshift[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
//十六进制转二进制
string trans16to2(string hexDigit) {
string binaryDigit;
for (int i = 0; i < hexDigit.length(); ++i) {
char e = hexDigit[i];
if (e >= 'A' && e <= 'F') {
int a = static_cast<int>(e - 'A' + 10);
switch (a) {
case 10:
binaryDigit += "1010";
break;
case 11:
binaryDigit += "1011";
break;
case 12:
binaryDigit += "1100";
break;
case 13:
binaryDigit += "1101";
break;
case 14:
binaryDigit += "1110";
break;
case 15:
binaryDigit += "1111";
break;
}
} else if (isdigit(e)) {
int b = static_cast<int>(e - '0');
switch (b) {
case 0:
binaryDigit += "0000";
break;
case 1:
binaryDigit += "0001";
break;
case 2:
binaryDigit += "0010";
break;
case 3:
binaryDigit += "0011";
break;
case 4:
binaryDigit += "0100";
break;
case 5:
binaryDigit += "0101";
break;
case 6:
binaryDigit += "0110";
break;
case 7:
binaryDigit += "0111";
break;
case 8:
binaryDigit += "1000";
break;
case 9:
binaryDigit += "1001";
break;
}
}
}
return binaryDigit;
};
//循环左移一位
string strol(string ss) {
int len = ss.length();
string ss1;
char temp = ss[0];
for (int i = 1; i < len; i++) {
ss1 += ss[i];
}
ss1 += temp;
return ss1;
};
bool isHexDigit(char c) {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
int main() {
system("chcp 65001");
//方便打印四个弱密钥
int n = 4;
while (n--){
string hexDigit_key;
cout << "请输入64位的秘钥,以16进制的方式输入:" << endl;
getline(cin,hexDigit_key);
string key;
for (char c : hexDigit_key) {
if (isHexDigit(c)) {
key+=c;
}
}
//转换成二进制
string binaryDigit = trans16to2(key);
cout << "秘钥转换成二进制之后:" << endl;
cout << binaryDigit << endl << endl;
string sPC1;
string K[16];
// 秘钥转换,转换成56位 64-->56
for (int i = 0; i < 56; i++) {
sPC1 += binaryDigit[PC1[i] - 1];
}
cout << "秘钥转换之后(64-->56): " << endl <<sPC1 << endl << endl;
string temp = sPC1;
string left = temp.substr(0, 28);
string right = temp.substr(28, 55);
for (int i = 0; i < 16; i++) {
int numlshift = lshift[i];
if (numlshift == 1) {
left = strol(left);
right = strol(right);
}
if (numlshift == 2) {
left = strol(left);
right = strol(right);
left = strol(left);
right = strol(right);
}
string ss;
ss += left;
ss += right;
for (int j = 0; j < 48; j++) {
K[i] += ss[PC2[j] - 1];
}
}
for (int k = 0; k < 16; k++) {
cout << "第" << k+1 << "轮的子密钥为:" << K[k] << endl;
}
cout << endl;
}
}
2.
#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
#include<fstream>
using namespace std;
string desKeys[20];
/**
*数据初始置换表
*/
int T1[8][8] = {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 T2[8][7] = {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,
3, 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 T3[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
/**
*密钥压缩置换表
*/
int T4[8][6] = {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 T5[8][6] = {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盒置换表
*/
int S[8][4][16] = {{{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}}};
/**
*P盒置换表
*/
int P[4][8] = {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 T6[8][8] = {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};
/**
*最终置换函数 64位->64位
*函数说明:s为完成最后一轮循环得到的64为数据
*返回值为密文或明文
*/
string final_permutation(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
rs += s[T6[i][j] - 1];
}
}
return rs;
}
/**
*P盒置换函数 32位->32位
*函数说明:s为S盒的输出
*/
string P_box(string s) {
string rs = "";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 8; j++) {
rs += (s[P[i][j] - 1]);
}
}
return rs;
}
/**
*S盒置换函数 48位->32位
*函数说明:s为48位数据
*返回值为32位
*/
string S_box(string s) {
string rs = "";
string s1;
int k1, k2;//S盒的行号和列号
int h = 1;//决定使用那个S盒
for (int i = 0; i <= 42; i = i + 6, h++) {
k1 = (s[i] - '0') * 2 + (s[i + 5] - '0') * 1;
k2 = (s[i + 1] - '0') * 8 + (s[i + 2] - '0') * 4 + (s[i + 3] - '0') * 2 + (s[i + 4] - '0') * 1;
int x = S[h - 1][k1][k2];
s1 = "";
int y = 8;
for (int j = 1; j <= 4; j++) {
if (x < y) {
s1 += "0";
y /= 2;
} else {
s1 += "1";
x = x % y;
y /= 2;
}
}
rs += s1;
}
return rs;
}
/**
*异或运算函数
*要求位数相同
*/
string desXOR(string s1, string s2) {
string rs = "";
for (int i = 0; i < s1.length() && i < s2.length(); i++) {
rs += ((s1[i] - '0') ^ (s2[i] - '0')) + '0';
}
return rs;
}
/**
*数据扩展函数 32->48
*函数说明:s为数据的右半部分 32位
*扩展成48位的输出
*/
string plaintext_righthalf_extended_permutation(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
rs += s[T5[i][j] - 1];
}
}
return rs;
}
/**
*密钥压缩置换函数 56位->48位
*函数说明:s为56为的密钥
*输出为48位的子密钥
*/
string secret_key_compression_replacement(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
rs += s[T4[i][j] - 1];
}
}
return rs;
}
/**
*密钥循环左移函数 56位->56位
*函数说明:k为左移位数 s为密钥
*返回值位数不变
*/
string secret_ket_left_move(int k, string s)//密钥循环左移k位
{
string s1 = s.substr(0, 28);
string s2 = s.substr(28, 28);
string rs = s1.substr(k, 28 - k) + s1.substr(0, k) + s2.substr(k, 28 - k) + s2.substr(0, k);
return rs;
}
/**
*密钥初始置换函数 64位->56位
*函数说明:s为64位的初始密钥
*返回值为56位
*/
string secret_key_initial_permutation(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
rs += s[T2[i][j] - 1];
}
}
return rs;
}
/**
*明文初始置换函数 64位->64位
*函数说明:s为初始明文 64位
*返回值为6位
*/
string plaintext_initial_permutation(string s)//明文初始置换
{
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
rs += s[T1[i][j] - 1];
}
}
return rs;
}
/**
*16进制转2进制函数
*函数说明:s为16进制字符串
*返回为2进制字符串
*/
string des_H(string s) {
string s1;
string rs = "";
for (int i = 0; i < s.length(); i++) {
int x;
if (s[i] >= '0' && s[i] <= '9') {
x = s[i] - '0';
} else {
x = s[i] - 'A' + 10;
}
s1 = "";
int y = 8;
for (int j = 1; j <= 4; j++) {
if (x < y) {
y /= 2;
s1 += "0";
} else {
s1 += "1";
x = x % y;
y = y / 2;
}
}
rs += s1;
}
return rs;
}
/**
*2进制转16进制函数
*str为2进制字符串
*返回值为16进制字符串
*/
string des_G(string str) {
string rs = "";
char temp;
for (int i = 0; i <= str.length() - 4; i = i + 4) {
int x = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + str[i + 3] - '0';
if (x >= 10) {
temp = (char) (x - 10 + 'A');
} else {
temp = (char) (x + '0');
}
rs += temp;
}
return rs;
}
/**
*封装函数f
*函数说明:接收32位数据和48位的子密钥 产生一个32位的输出
*str1:32位数据 str2:48位的子密钥
*返回值32位
*/
string des_f(string str1, string str2) {
string expendR = plaintext_righthalf_extended_permutation(str1);
//cout<<"32位数据扩展为48位结果:"<<expendR<<endl;
string rs = desXOR(expendR, str2);
//cout<<"密钥和扩展数据异或结果:"<<rs<<endl;
rs = S_box(rs);
//cout<<"S盒替代结果(48->32):"<<rs<<endl;
rs = P_box(rs);
//cout<<"P盒替代结果(32->32):"<<rs<<endl;
return rs;
}
/**
*子密钥生成函数
*函数说明:s为给定的密钥
*生成16个子密钥
*/
void des_generateKeys(string s) {
s = secret_key_initial_permutation(s);
for (int i = 1; i <= 16; i++) {
s = secret_ket_left_move(T3[i - 1], s);
desKeys[i] = secret_key_compression_replacement(s);
}
}
/*
* 明文字符串转换成0/1字符串
*/
string des_StrToBitStr(string str) {
bitset<64> bstr;
for (int i = 0; i < 8; i++) {
bitset<8> bits = bitset<8>(str[i]);
for (int j = 0; j < 8; j++) {
bstr[i * 8 + j] = bits[7 - j];
}
}
string s = bstr.to_string();
//添加一个翻转操作
reverse(begin(s), end(s));
return s;
}
/*
* 0/1字符串装换为字符形式的字符串
*/
string des_BitStrToStr(string bstr) {
string str = "";
//每八位转化成十进制,然后将数字结果转化成字符
int sum;
for (int i = 0; i < bstr.size(); i += 8) {
sum = 0;
for (int j = 0; j < 8; j++)
if (bstr[i + j] == '1')
sum = sum * 2 + 1;
else
sum = sum * 2;
str = str + char(sum);
}
return str;
}
string chardeel(string &str1, string &str2) {
string temp_str = "";
int divi_times = (str1.size() % 8 ? str1.size() / 8 + 1 : str1.size() / 8); //计算分组个数
for (int i = 0; i < divi_times; ++i) { //每个分组单独转换成二进制串
string str1_temp = str1.substr(8 * i, 8); //substr(start,len)
bool jude = false;
int addchar = 0;
if (str1_temp.size() % 8) {
jude = true;
addchar = 8 - str1_temp.size() % 8;
}
int sub = str1_temp.size() * 8;
if (jude) {
for (int i = 0; i < addchar; ++i) {
str1_temp += 'a';
}
}
str1_temp = des_StrToBitStr(str1_temp);
if (jude) {
for (int i = 0; i < addchar * 8; ++i) {
str1_temp[sub + i] = '0';
}
}
temp_str = temp_str + str1_temp;
}
str2 = des_H(str2);
return temp_str;
}
/**
*DES加密函数 64位->64位
*函数说明:str1为64位的给定明文
*返回值为64位的密文
*/
string des_encrypt(string str1, string str2) {
//str1是要明文,str2是密文
str1 = chardeel(str1, str2); //明文分组和填充,返回01字符串
des_generateKeys(str2); //生成16个子密钥
int divi_times = str1.size() / 64; //分成多少组去进行des
string rs_final = "";
for (int i = 0; i < divi_times; ++i) {
string str1_temp = str1.substr(i * 64, 64);
//第一步:明文初始置换 64->64
str1_temp = plaintext_initial_permutation(str1_temp);
//第二步:数据分组
string left = str1_temp.substr(0, 32);
string right = str1_temp.substr(32, 32);
string newleft;
//第三步:16轮迭代
for (int i = 1; i <= 16; i++) {
newleft = right;
right = desXOR(left, des_f(right, desKeys[i]));
left = newleft;
}
//第四步:合并数据 注意位R16L16
string rs = right + left;
//结尾置换,最后一次置换
rs = final_permutation(rs);
rs_final = rs_final + rs;
}
return rs_final;
}
/**
*解密函数
*str为密文
*输出明文
*/
string des_decrypt(string str) {
int divi_times = str.size() / 64; //分成多少组去进行des
string rs_temp = "";
for (int i = 0; i < divi_times; ++i) {
string str_temp = str.substr(i * 64, 64);
//把密文当作明文进行初始明文置换
str_temp = plaintext_initial_permutation(str_temp);
//左右分组
string left = str_temp.substr(0, 32);
string right = str_temp.substr(32, 32);
string newleft;
//逆序的子密钥使用 16轮迭代
for (int i = 16; i >= 1; i--) {
newleft = right;
right = desXOR(left, des_f(right, desKeys[i]));
left = newleft;
}
//合并
string rs = right + left;
//最后置换
rs = final_permutation(rs);
rs_temp = rs_temp + rs;
}
rs_temp = des_BitStrToStr(rs_temp);
// cout << " 11111 " << endl;
return rs_temp;
}
//将二进制密文转换为16进制显示
std::string binaryToString(const std::string& binary_str) {
std::string result;
// 将二进制字符串按照8位一组进行分割,并将每组转换为对应的字符
for (size_t i = 0; i < binary_str.size(); i += 8) {
std::string sub_str = binary_str.substr(i, 8);
std::bitset<8> bits(sub_str);
int decimal = bits.to_ulong();
char ch = static_cast<char>(decimal);
result += ch;
}
return result;
}
int main() {
//用于控制台打印中文字符
system("chcp 65001");
string str2 = "";
cout << "请输入密钥:(秘钥格式为16为的字符,然后用代码转换为2进制)" << endl;
getline(cin, str2);
ifstream ifs;
// 3打开文件并判断是否打开成功
ifs.open("C:\\Users\\ASUS\\Desktop\\3434\\111.txt", ios::in);
if (!ifs.is_open()) {
cout << "打开失败" << endl;
}
//读数据
char buf[1024] = {0};
string rs;
while (ifs >> buf) {
string str1 = buf;
rs += buf;
rs += " ";
}
cout << "****************明文***************" << endl;
cout << "获取到的明文信息:" << endl << rs << endl << endl;
//加密
rs = des_encrypt(rs, str2);
cout << "****************加密***************" << endl;
cout << "加密后的密文:" << endl << rs << endl;
std::string result = binaryToString(rs);
std::cout << "加密后的密文(字符形式): " << result << std::endl << endl;
//解密
rs = des_decrypt(rs);
cout << "****************解密***************" << endl;
cout << "解密后的明文:" << rs << endl;
return 0;
}
3.
#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
#include<fstream>
using namespace std;
string desKeys[20];
/**
*数据初始置换表
*/
int T1[8][8] = {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 T2[8][7] = {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,
3, 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 T3[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
/**
*密钥压缩置换表
*/
int T4[8][6] = {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 T5[8][6] = {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盒置换表
*/
int S[8][4][16] = {{{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}}};
/**
*P盒置换表
*/
int P[4][8] = {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 T6[8][8] = {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};
/**
*最终置换函数 64位->64位
*函数说明:s为完成最后一轮循环得到的64为数据
*返回值为密文或明文
*/
string final_permutation(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
rs += s[T6[i][j] - 1];
}
}
return rs;
}
/**
*P盒置换函数 32位->32位
*函数说明:s为S盒的输出
*/
string P_box(string s) {
string rs = "";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 8; j++) {
rs += (s[P[i][j] - 1]);
}
}
return rs;
}
/**
*S盒置换函数 48位->32位
*函数说明:s为48位数据
*返回值为32位
*/
string S_box(string s) {
string rs = "";
string s1;
int k1, k2;//S盒的行号和列号
int h = 1;//决定使用那个S盒
for (int i = 0; i <= 42; i = i + 6, h++) {
k1 = (s[i] - '0') * 2 + (s[i + 5] - '0') * 1;
k2 = (s[i + 1] - '0') * 8 + (s[i + 2] - '0') * 4 + (s[i + 3] - '0') * 2 + (s[i + 4] - '0') * 1;
int x = S[h - 1][k1][k2];
s1 = "";
int y = 8;
for (int j = 1; j <= 4; j++) {
if (x < y) {
s1 += "0";
y /= 2;
} else {
s1 += "1";
x = x % y;
y /= 2;
}
}
rs += s1;
}
return rs;
}
/**
*异或运算函数
*要求位数相同
*/
string desXOR(string s1, string s2) {
string rs = "";
for (int i = 0; i < s1.length() && i < s2.length(); i++) {
rs += ((s1[i] - '0') ^ (s2[i] - '0')) + '0';
}
return rs;
}
/**
*数据扩展函数 32->48
*函数说明:s为数据的右半部分 32位
*扩展成48位的输出
*/
string plaintext_righthalf_extended_permutation(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
rs += s[T5[i][j] - 1];
}
}
return rs;
}
/**
*密钥压缩置换函数 56位->48位
*函数说明:s为56为的密钥
*输出为48位的子密钥
*/
string secret_key_compression_replacement(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
rs += s[T4[i][j] - 1];
}
}
return rs;
}
/**
*密钥循环左移函数 56位->56位
*函数说明:k为左移位数 s为密钥
*返回值位数不变
*/
string secret_ket_left_move(int k, string s)//密钥循环左移k位
{
string s1 = s.substr(0, 28);
string s2 = s.substr(28, 28);
string rs = s1.substr(k, 28 - k) + s1.substr(0, k) + s2.substr(k, 28 - k) + s2.substr(0, k);
return rs;
}
/**
*密钥初始置换函数 64位->56位
*函数说明:s为64位的初始密钥
*返回值为56位
*/
string secret_key_initial_permutation(string s) {
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
rs += s[T2[i][j] - 1];
}
}
return rs;
}
/**
*明文初始置换函数 64位->64位
*函数说明:s为初始明文 64位
*返回值为6位
*/
string plaintext_initial_permutation(string s)//明文初始置换
{
string rs = "";
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
rs += s[T1[i][j] - 1];
}
}
return rs;
}
/**
*16进制转2进制函数
*函数说明:s为16进制字符串
*返回为2进制字符串
*/
string des_H(string s) {
string s1;
string rs = "";
for (int i = 0; i < s.length(); i++) {
int x;
if (s[i] >= '0' && s[i] <= '9') {
x = s[i] - '0';
} else {
x = s[i] - 'A' + 10;
}
s1 = "";
int y = 8;
for (int j = 1; j <= 4; j++) {
if (x < y) {
y /= 2;
s1 += "0";
} else {
s1 += "1";
x = x % y;
y = y / 2;
}
}
rs += s1;
}
return rs;
}
/**
*2进制转16进制函数
*str为2进制字符串
*返回值为16进制字符串
*/
string des_G(string str) {
string rs = "";
char temp;
for (int i = 0; i <= str.length() - 4; i = i + 4) {
int x = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + str[i + 3] - '0';
if (x >= 10) {
temp = (char) (x - 10 + 'A');
} else {
temp = (char) (x + '0');
}
rs += temp;
}
return rs;
}
/**
*封装函数f
*函数说明:接收32位数据和48位的子密钥 产生一个32位的输出
*str1:32位数据 str2:48位的子密钥
*返回值32位
*/
string des_f(string str1, string str2) {
string expendR = plaintext_righthalf_extended_permutation(str1);
//cout<<"32位数据扩展为48位结果:"<<expendR<<endl;
string rs = desXOR(expendR, str2);
//cout<<"密钥和扩展数据异或结果:"<<rs<<endl;
rs = S_box(rs);
//cout<<"S盒替代结果(48->32):"<<rs<<endl;
rs = P_box(rs);
//cout<<"P盒替代结果(32->32):"<<rs<<endl;
return rs;
}
/**
*子密钥生成函数
*函数说明:s为给定的密钥
*生成16个子密钥
*/
void des_generateKeys(string s) {
s = secret_key_initial_permutation(s);
for (int i = 1; i <= 16; i++) {
s = secret_ket_left_move(T3[i - 1], s);
desKeys[i] = secret_key_compression_replacement(s);
}
}
/*
* 明文字符串转换成0/1字符串
*/
string des_StrToBitStr(string str) {
bitset<64> bstr;
for (int i = 0; i < 8; i++) {
bitset<8> bits = bitset<8>(str[i]);
for (int j = 0; j < 8; j++) {
bstr[i * 8 + j] = bits[7 - j];
}
}
string s = bstr.to_string();
//添加一个翻转操作
reverse(begin(s), end(s));
return s;
}
/*
* 0/1字符串装换为字符形式的字符串
*/
string des_BitStrToStr(string bstr) {
string str = "";
//每八位转化成十进制,然后将数字结果转化成字符
int sum;
for (int i = 0; i < bstr.size(); i += 8) {
sum = 0;
for (int j = 0; j < 8; j++)
if (bstr[i + j] == '1')
sum = sum * 2 + 1;
else
sum = sum * 2;
str = str + char(sum);
}
return str;
}
string chardeel(string &str1, string &str2) {
string temp_str = "";
int divi_times = (str1.size() % 8 ? str1.size() / 8 + 1 : str1.size() / 8); //计算分组个数
for (int i = 0; i < divi_times; ++i) { //每个分组单独转换成二进制串
string str1_temp = str1.substr(8 * i, 8); //substr(start,len)
bool jude = false;
int addchar = 0;
if (str1_temp.size() % 8) {
jude = true;
addchar = 8 - str1_temp.size() % 8;
}
int sub = str1_temp.size() * 8;
if (jude) {
for (int i = 0; i < addchar; ++i) {
str1_temp += 'a';
}
}
str1_temp = des_StrToBitStr(str1_temp);
if (jude) {
for (int i = 0; i < addchar * 8; ++i) {
str1_temp[sub + i] = '0';
}
}
temp_str = temp_str + str1_temp;
}
str2 = des_H(str2);
return temp_str;
}
/**
*DES加密函数 64位->64位
*函数说明:str1为64位的给定明文
*返回值为64位的密文
*/
string des_encrypt(string str1, string str2) {
//str1是要明文,str2是密文
str1 = chardeel(str1, str2); //明文分组和填充,返回01字符串
des_generateKeys(str2); //生成16个子密钥
int divi_times = str1.size() / 64; //分成多少组去进行des
string rs_final = "";
for (int i = 0; i < divi_times; ++i) {
string str1_temp = str1.substr(i * 64, 64);
//第一步:明文初始置换 64->64
str1_temp = plaintext_initial_permutation(str1_temp);
//第二步:数据分组
string left = str1_temp.substr(0, 32);
string right = str1_temp.substr(32, 32);
string newleft;
//第三步:16轮迭代
for (int i = 1; i <= 16; i++) {
newleft = right;
right = desXOR(left, des_f(right, desKeys[i]));
left = newleft;
}
//第四步:合并数据 注意位R16L16
string rs = right + left;
//结尾置换,最后一次置换
rs = final_permutation(rs);
rs_final = rs_final + rs;
}
return rs_final;
}
/**
*解密函数
*str为密文
*输出明文
*/
string des_decrypt(string str) {
int divi_times = str.size() / 64; //分成多少组去进行des
string rs_temp = "";
for (int i = 0; i < divi_times; ++i) {
string str_temp = str.substr(i * 64, 64);
//把密文当作明文进行初始明文置换
str_temp = plaintext_initial_permutation(str_temp);
//左右分组
string left = str_temp.substr(0, 32);
string right = str_temp.substr(32, 32);
string newleft;
//逆序的子密钥使用 16轮迭代
for (int i = 16; i >= 1; i--) {
newleft = right;
right = desXOR(left, des_f(right, desKeys[i]));
left = newleft;
}
//合并
string rs = right + left;
//最后置换
rs = final_permutation(rs);
rs_temp = rs_temp + rs;
}
rs_temp = des_BitStrToStr(rs_temp);
// cout << " 11111 " << endl;
return rs_temp;
}
std::string binaryToString(const string binary_str) {
std::string result = "";
// 将二进制字符串按照8位一组进行分割,并将每组转换为对应的字符
for (int i = 0; i < binary_str.size(); i += 8) {
std::string sub_str = binary_str.substr(i, 8);
std::bitset<8> bits(sub_str);
int decimal = bits.to_ulong();
char ch = static_cast<char>(decimal);
result += ch;
}
// cout << "?";
// cout << binary_str << endl;
// cout << "result: " << result;
return result;
}
int main() {
//用于控制台打印中文字符
system("chcp 65001");
cout << "****************DES加密***************" << endl;
string str2 = "";
cout << "请输入密钥:(秘钥格式为16为的字符,然后用代码转换为2进制)" << endl;
getline(cin, str2);
string plaintext;
cout << "****************明文***************" << endl;
cout << "请输入明文:" ;
getline(cin, plaintext);
//加密
plaintext = des_encrypt(plaintext, str2);
cout << "****************加密***************" << endl;
cout << "加密后的密文:" << endl << plaintext << endl;
string temp_re = plaintext;
string result = binaryToString(temp_re);
cout << "密文(字符形式): " << result << endl << endl;
//解密
plaintext = des_decrypt(plaintext);
cout << "****************解密***************" << endl;
cout << "解密后的明文:" << plaintext << endl;
return 0;
}
四、实验结果
1.
2.
3.
由于是分组密码,所以秘钥不变,相应的分组加密之后不会变.