DES代码实现
DES整体思路不难,大部分都是将bit数组的每一位以交换表对应位置的数字作为下标进行重排。本文仅进行代码分析,算法原理请留意我的另一篇算法描述的博客
效果分析
本程序实现的是输入一段任意字符串(无空格,可使用中文),通过加解密,可以输出密文和解密后得到的明文
代码分析
使用到的数据类型
为节省内存,本程序使用了bitset数据类型,每段明文被初始分解成64bit进行操作,用于S-盒数据过多,直接使用文件I/O进行读写,使用了二进制转十进制的转换函数strtol
和任意进制转二进制的函数_itoa_s()
.
ps : _itoa_s() 是visual stdio 支持的比较“安全”的itoa(),其他平台使用的是 itoa();
运行代码前,请将DES.cpp 中Intial_Sbox 的filename 改成你本地的S-盒存储路径
两个数据处理函数:
1.StrToBit(string )
将字符串转成二进制串,用于输入明文
bitset<64> DES::StrToBit(string a)
{
bitset<64> bits;
for (int i = 0; i<8; ++i)
for (int j = 0; j<8; ++j)
bits[i * 8 + j] = ((a[i] >> j) & 1);
return bits;
}
2.BitToStr(bitset<64> a)
将二进制串转成字符串,用于输出可视化的信息(如解密得到明文或者密文)
string DES::BitToStr(bitset<64> a)
{
bitset<8> temp;
char **endptr = NULL;
int num;
string str = "";
for (int i = 0; i < 64; i++)
{
temp[i % 8] = a[i];
if (i % 8 == 7)
{
num = strtol(temp.to_string().c_str(), endptr, 2);
char a = num;
str += a;
}
}
return str;
}
S-盒数据,每个S-盒共有64个数据,共8个S-盒:
14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7 0 15 7 4 15 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 12 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
DES.cpp
#include <iostream>
#include <cstdlib>
#include <fstream>
#include "DES.hpp"
using namespace std;
DES::DES()
{
//初始化密钥
bitset<64> ckey("1010101010110101010010101010110101110101010101001001010100010101");
ChiperKey = ckey;
//加载S-盒数据
Intial_Sbox();
//生成子密钥
Generate_key();
}
void DES::initial(string str)
{
while (str.length() < 8)
{
str += '0';
}
PlainText = StrToBit(str);
}
void DES::initialChiper(string str)
{
ChiperText = StrToBit(str);
}
DES::~DES()
{
SBox.clear();
}
void DES::IP(int num)
{
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 };
int t;
bitset<64> temp;
if (num == 0)
{
temp = PlainText;
}
else
{
temp = ChiperText;
}
for (int i = 0; i < 64; i++)
{
t = ip[i]-1;
Temp[i] = temp[t];
}
}
//IP置换
string DES::IP1()
{
int ip1[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 };
bitset<64> result;
for (int i = 0; i < 64; i++)
{
result[i] = Temp[ip1[i] - 1];
}
return BitToStr(result);
}
//Feistel轮函数,包括E扩展和S-盒压缩
bitset<32> DES::Feistel(bitset<32>& R0, bitset<48>& k)
{
//E-expend
int index[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};
bitset<48> E_expand;
int t;
for (int i = 0; i < 48; i++)
{
t = index[i] - 1;
E_expand[i] = R0[t];
}
//XOR
E_expand ^= k;
//divide into 8 group
bitset<6> group[8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 6; j++)
{
group[i][j] = E_expand[j + i * 6];
}
}
// use long int strtol(const char *nptr, char **endptr, int base)
//to translate any base number to decimalism
// use char * itoa(int number , char *str,int base)
// to translate decimalism to any base number
bitset<6> row;
bitset<6> col;
bitset<6> row_and("100001");
bitset<6> col_and("011110");
bitset<6> temp_and("000001");
vector<bitset<4>> bit;
int select_row;
int select_col;
char **endptr = NULL;
for (int i = 0; i < 8; i++)
{
row = group[i] & row_and;
row = (row >> 5) | (row & temp_and);
col = group[i] & col_and;
col = col >> 1;
select_row = strtol(row.to_string().c_str(), endptr, 2);
select_col = strtol(col.to_string().c_str(), endptr, 2);
int num = S_Block(i, select_row, select_col);
char str[5] = "";
//translate num to binary number
_itoa_s(num, str,5, 2);//4 parameter
bitset<4> temp(str);
bit.push_back(temp);
}
bitset<32> feistel;
t = 0;
for (int i = 0; i < bit.size(); i++)
{
for (int j = 0; j < 4; j++)
{
feistel[t++] = bit[i][j];
}
}
bit.clear();
feistel = P_permutation(feistel);
return feistel;
}
void DES::Generate_key()
{
int pc[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 };
bitset<28> C0;
bitset<28> D0;
int t;
for (int i = 0; i < 28; i++)
{
t = pc[i]-1;
C0[i] = ChiperKey[t];
t = pc[i + 28] - 1;
D0[i] = ChiperKey[t];
}
t = 1;
int shift;
while (t < 17)
{
switch (t)
{
case 1:
case 2:
case 9:
case 16:shift = 1; break;
default:
shift = 2;
break;
}
int index;
C0 = (C0 >> (28 - shift))| (C0 << shift);
D0 = (D0 >> (28 - shift))| (D0 << shift);
for (int i = 0; i < 48; i++)
{
index = pc2[i] - 1;
if (index < 28)
{
key[t][i] = C0[index];
}
else
{
key[t][i] = D0[index - 28];
}
}
t++;
}
}
int DES::S_Block(int i,int row,int col)
{
int index = i * 64 + row * 16 + col;
return SBox[index];
}
bitset<32> DES::P_permutation(bitset<32> &feistel)
{
int p[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 };
bitset<32>temp;
for (int i = 0; i < 32; i++)
{
temp[i] = feistel[p[i] - 1];
}
return temp;
}
void DES::Transfer()
{
bitset<32> L0;
bitset<32> R0;
bitset<32> L1;
bitset<32> R1;
for (int i = 0; i < 32; i++)
{
L0[i] = Temp[i];
R0[i] = Temp[i + 32];
}
int t = 1;
bitset<32> feistel;
while (t <= 16)
{
L1 = R0;
feistel = Feistel(R0, key[t]);
R1 = L0 ^ feistel;
L0 = L1;
R0 = R1;
t++;
}
for (int i = 0; i < 32; i++)
{
Temp[i] = R1[i];
Temp[i + 32] = L1[i];
}
}
void DES::Intial_Sbox()
{
//运行前,先修改为你的S-盒存储路径
string filename = "your absolute s-box path ";
ifstream inSboxData;
inSboxData.open(filename.c_str(), ios::in);
int t = 0;
int temp;
vector<int> VecTemp;
while (!inSboxData.eof())
{
inSboxData >> temp;
SBox.push_back(temp);
}
inSboxData.close();
}
void DES::InverseTransfer()
{
bitset<32> A;
bitset<32> B;
bitset<32> G;
bitset<32> H;
for (int i = 0; i < 32; i++)
{
A[i] = Temp[i];
B[i] = Temp[i + 32];
}
int t = 16;
while (t > 0)
{
G = B;//G = L_t = R_t-1;
H = A ^ Feistel(B, key[t]);//H = Li-1
B = H;// B = Lt;
A = G;// A = Rt;
t--;
}
for (int i = 0; i < 32; i++)
{
Temp[i] = H[i];
Temp[i + 32] = G[i];
}
}
bitset<64> DES::StrToBit(string a)
{
bitset<64> bits;
for (int i = 0; i<8; ++i)
for (int j = 0; j<8; ++j)
bits[i * 8 + j] = ((a[i] >> j) & 1);
return bits;
}
string DES::BitToStr(bitset<64> a)
{
bitset<8> temp;
char **endptr = NULL;
int num;
string str = "";
for (int i = 0; i < 64; i++)
{
temp[i % 8] = a[i];
if (i % 8 == 7)
{
num = strtol(temp.to_string().c_str(), endptr, 2);
char a = num;
str += a;
}
}
return str;
}
DES.hpp
#ifndef DES_HPP
#define DES_HPP
#include <iostream>
#include <string>
#include <bitset>
#include <vector>
using namespace std;
class DES
{
public:
DES();
~DES();
void initial(string str);
void initialChiper(string str);
void IP(int);
string IP1();
bitset<32> Feistel(bitset<32>& R0,bitset<48> &k);//轮函数
void Generate_key();
int S_Block(int i, int row, int col);
bitset<32> P_permutation(bitset<32> &feistel);//P置换
void Transfer();//加密过程的子密钥调度
void Intial_Sbox();//从本地加载S-盒数据
void InverseTransfer();//解密过程的子密钥调度
bitset<64> StrToBit(string );
string BitToStr(bitset<64> a);
private:
std::bitset<64> PlainText;
std::bitset<64> ChiperText;
std::bitset<64> ChiperKey;
std::bitset<64> Temp;
std::bitset<48> key[17];
vector<int> SBox;
};
#endif
main.cpp
#include <iostream>
#include <string>
#include "DES.hpp"
using namespace std;
int main()
{
int sign;
cout << "input 0 to encode\ninput 1 to decode\ninput 2 to get the chiper text\n";
string a;
string b;
string str = "";
string plain = "";
DES des;
while (1)
{
cin >> sign;
if (sign == 0)
{
str = "";
cout << "please input the message" << endl;
cin >> a;
for (int i = 0; i < a.length(); i+= 8)
{
b = a.substr(i, 8);
des.initial(b);
des.IP(0);
des.Transfer();
str += des.IP1();
}
cerr << str << endl;
}
else if (sign == 1) {
if (str.length() == 0) {
cout << "please encode first" << endl;
continue;
}
plain = "";
for (int i = 0; i < str.length(); i += 8)
{
b = str.substr(i, 8);
des.initialChiper(b);
des.IP(1);
des.InverseTransfer();
plain += des.IP1();
}
if (a.length() % 8 != 0)
{
plain = plain.substr(0, a.length());
}
cout << plain << endl;
}
else if (sign == 2) {
if (str.length() == 0) {
cout << "please encode first" << endl;
continue;
}
cout << str << endl;
}
}
return 0;
}