# 原理

DES算法为密码体制中的对称密码体制，又被称为美国数据加密标准。

DES是一个分组加密算法，典型的DES以64位为分组对数据加密，加密和解密用的基本上是同一个算法。其密钥长64位，密钥事实上是56位参与DES运算（第8、16、24、32、40、48、56、64位是校验位，使得每个密钥都有奇数个1），分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。

DES算法大致流程为：初始IP置换 -> 密钥生成 -> 迭代变换（16轮）-> IP逆置换 -> 得到密文

# 流程

## 初始IP置换

int data[65], data_L[65], data_R[65]; // 输入明文的二进制

int IP_Init[65] = // IP初始置换表
{
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
};

void IP_InitTrans() // IP初始置换算法
{
int tmp[65];
for (int i = 0; i < 64; ++i) tmp[i] = data[i];
for (int i = 0; i < 64; ++i) data[i] = tmp[IP_Init[i]];
for (int i = 0; i < 32; ++i) data_L[i] = data[i];
for (int i = 32; i < 64; ++i) data_R[i - 32] = data[i];
}


## 密钥生成

int key[65], key_trans[65], key_L[65], key_R[65];
int key_mov[17] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

int Key_Init[57] = // 密钥初始置换表
{
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 key_comp[65] =
{
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
};
void Key_InitTrans() // 密钥初始置换算法
{
for (int i = 0; i < 56; ++i) key_trans[i] = key[Key_Init[i]];

for (int i = 0; i < 28; ++i) key_L[i] = key_trans[i];
for (int i = 28; i < 56; ++i) key_R[i - 28] = key_trans[i];

int tmp_1, tmp_2, tmp_3, tmp_4;
for (int i = 0; i < 16; ++i)
{
if (key_mov[i] == 1) // 左移一位
{
tmp_1 = key_L[0], tmp_2 = key_R[0];
for (int j = 0; j < 27; ++j) key_L[j] = key_L[j + 1], key_R[j] = key_R[j + 1];
key_L[27] = tmp_1, key_R[27] = tmp_2;
}
else // 左移两位
{
tmp_1 = key_L[0], tmp_2 = key_L[1], tmp_3 = key_R[0], tmp_4 = key_R[1];
for (int j = 0; j < 26; ++j) key_L[j] = key_L[j + 2], key_R[j] = key_R[j + 2];
key_L[26] = tmp_1, key_L[27] = tmp_2, key_R[26] = tmp_3, key_R[27] = tmp_4;
}
}
for (int i = 0; i < 28; ++i) key_trans[i] = key_L[i];
for (int i = 28; i < 56; ++i) key_trans[i] = key_R[i - 28];

for (int i = 0; i < 48; ++i) key[i] = key_trans[key_comp[i]];

}


## 迭代变换（16轮）

int E_Extend[50] =
{
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
};

int s[10][5][17] =
{
{ // 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}
}
};

void S_Rep()
{
int tmp[65];
for (int i = 0; i < 48; ++i) tmp[i] = data_R[i];
int tmp_1 = 0, tmp_2 = 0, x = 0, y = 0;
for (int i = 0; i < 8; ++i)
{
tmp_1 = i * 6, tmp_2 = i * 2;
x = (tmp[tmp_1] << 1) + (tmp[tmp_1 + 5]);
y = (tmp[tmp_1 + 1] << 3 + tmp[tmp_1 + 2] << 2 + tmp[tmp_1 + 3] << 1 + tmp[tmp_1 + 4]);
int out = s[i][x][y];
data_R[tmp_2] = out % 2, out /= 2;
data_R[tmp_2 + 1] = out % 2, out /= 2;
data_R[tmp_2 + 2] = out % 2, out /= 2;
data_R[tmp_2 + 3] = out % 2, out /= 2;
}
}

int P_Rep[33] =
{
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
};

void des_main()
{
int tmp[50];
for (int i = 0; i < 32; ++i) tmp[i] = data_R[i];
for (int i = 0; i < 48; ++i) data_R[i] = tmp[E_Extend[i]];

for (int i = 0; i < 48; ++i) data_R[i] ^= key[i];

S_Rep();
for (int i = 0; i < 32; ++i) tmp[i] = data_R[i];
for (int i = 0; i < 32; ++i) data_R[i] = tmp[P_Rep[i]];
}

void Encrypt()
{
int tmp_L[50], tmp_R[50];
for (int t = 1; t <= 16; ++t)
{
for (int i = 0; i < 32; ++i) tmp_L[i] = data_L[i], tmp_R[i] = data_R[i];
des_main();
for (int i = 0; i < 32; ++i)
{
data_L[i] = tmp_R[i];
data_R[i] ^= tmp_L[i];
}
}
for (int i = 0; i < 32; ++i) tmp_L[i] = data_L[i], tmp_R[i] = data_R[i];
for (int i = 0; i < 32; ++i) data_L[i] = tmp_R[i], data_R[i] = tmp_L[i];
}


## 逆初始置换

16轮迭代后将$$L_{16}$$$$R_{16}$$合并，形成64位二进制，然后按照下表进行逆初始置换，得到最终的64位密文

int IP_RevInit[65] =
{
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
};

void IP_RevTrans()
{
int tmp[65];
for (int i = 0; i < 32; ++i) data[i] = data_L[i];
for (int i = 32; i < 64; ++i) data[i] = data_R[i - 32];
for (int i = 0; i < 64; ++i) tmp[i] = data[i];
for (int i = 0; i < 64; ++i) data[i] = tmp[IP_RevInit[i]];
}


# 解密过程

DES算法的解密和加密是一个原理，算法也基本类似，只有少数地方不同

• 若加密时子密钥的使用顺序是K1, K2...K16，那么解密时顺序就是K16, K15...K1
• 加密生成密钥时是循环左移，解密生成密钥时是循环右移

# 网上嫖的一个轮子

//经过上述对DES算法每一步的深入研究分析，在理论上对DES算法的实现有了较为清晰的思路，笔者将依据上述理论分析，在Windows10操作系统下，利用Codeblocks开发环境，采用C++11标准对DES算法进行代码实现。
//笔者特别说明，为了简便话，笔者使用随机数来生成算法所需的各个表格，并且在加密和解密过程中用到的密钥相同，参照表格相同。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<ctime>
using namespace std;

char plaintext[8];//明文8字符,64位
char key[16];//秘钥,16个16进制数，64位
char ciphertext[16];//密文,16个16进制数，64位

int PC_1[8][7];//64位秘钥转成56位秘钥所用表
int left_move_table[16];//循环左移参照表
int PC_2[8][6];//cidi56位秘钥转成48位秘钥ki所用表
int E_bit_selection_table[8][6];//在f函数执行期间，转换Ri用到的参照表

int IP_1[8][8];//initial permutation ，64位数据第一次变换参照的表
int S[8][4][16];//8个S盒
int sub_key[17][48];//16个子秘钥,k1到k16
int P[8][4];//
int IP_2[8][8];//最后一次变换所参照的表
int L[17][32],R[17][32];//数据加密阶段，产生16对数据块1到16分别存放

void init();//初始化各个参照表
void hex_bin(char x,int tmp[]);//16进制数x转成4位二进制
void bin_hex(int tmp[4],char &c);//4位2进制转16进制，结果存放在字符c中
void circle_left_move(int a[],int step);//循环左移，这里只有28位的秘钥，左移step位
void make_sub_key();//产生子秘钥

void exclusive_or(int a[],int b[],int n,int result[]);//异或,a数组,b数组表示的两个n位二进制数进行异或
void make_random(int n,int s[]);//产生n个随机数，放在数组a中

void f(int n,int P_end[32]);//得到的f存到P_end数组中
void des();//执行DES算法
void decode();//解密

void go();//程序控制

int main()
{
go();
return 0;
}

//产生n个互不相同的数分别是1-n
void make_random(int n,int s[]){
int a[64];
int index=0;
for(int i=0;i<n;i++){
a[i]=i+1;
}
srand(unsigned(time(0)));//播种子
for(int i=0;i<n;){
index=rand()%n;
if(a[index]!=0){
s[i]=a[index];
a[index]=0;
i++;
}
}
}

void init(){
int s[64];//存放产生的随机数
int cnt=0;
//初始化PC_1表（64位秘钥转56位秘钥参照表）
make_random(64,s);
cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<7;j++){
PC_1[i][j]=s[cnt++];
}
}

//初始化循环左移表left_move_table
for(int i=0;i<16;i++){
left_move_table[i]=rand()%6+1;//这里假设循环左移1到6位
}

//初始化PC_2表（56位秘钥转48位秘钥参照表）
make_random(48,s);
cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<6;j++){
PC_2[i][j]=s[cnt++];
}
}

//初始化IP_1表（64位原始数据转成新的64位数据块
make_random(64,s);
cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
IP_1[i][j]=s[cnt++];
}
}

//初始化E_bit_selection_table，在f函数执行期间对Ri转换下
//32位扩到48位，只能在1-32选取
for(int i=0;i<8;i++){
for(int j=0;j<6;j++){
E_bit_selection_table[i][j]=rand()%32+1;
}
}

//初始化S盒
for(int i=0;i<8;i++){
for(int j=0;j<4;j++){
make_random(16,s);
cnt=0;
for(int k=0;k<16;k++){
s[k]-=1;
}
for(int k=0;k<16;k++){
S[i][j][k]=s[cnt++];
}
}
}

//初始P，8个盒子已经搞完了一遍
make_random(32,s);
cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<4;j++){
P[i][j]=s[cnt++];
}
}

//初始化最后一个表IP_2
make_random(64,s);
cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
IP_2[i][j]=s[cnt++];
}
}
}

//一个十六进制数转成4位二进制数
void hex_bin(char x,int tmp[]){
int a,b,c,d;
if('0'==x){a=0;b=0;c=0;d=0;}
else if('1'==x){a=0;b=0;c=0;d=1;}
else if('2'==x){a=0;b=0;c=1;d=0;}
else if('3'==x){a=0;b=0;c=1;d=1;}
else if('4'==x){a=0;b=1;c=0;d=0;}
else if('5'==x){a=0;b=1;c=0;d=1;}
else if('6'==x){a=0;b=1;c=1;d=0;}
else if('7'==x){a=0;b=1;c=1;d=1;}
else if('8'==x){a=1;b=0;c=0;d=0;}
else if('9'==x){a=1;b=0;c=0;d=1;}
else if('a'==x || 'A'==x){a=1;b=0;c=1;d=0;}
else if('b'==x || 'B'==x){a=1;b=0;c=1;d=1;}
else if('c'==x || 'C'==x){a=1;b=1;c=0;d=0;}
else if('d'==x || 'D'==x){a=1;b=1;c=0;d=1;}
else if('e'==x || 'E'==x){a=1;b=1;c=1;d=0;}
else if('f'==x || 'F'==x){a=1;b=1;c=1;d=1;}
tmp[0]=a;tmp[1]=b;tmp[2]=c;tmp[3]=d;
}

void bin_hex(int tmp[4],char &c){
int sum=tmp[0]*8+tmp[1]*4+tmp[2]*2+tmp[3]*1;
if(sum>=0 && sum<=9){
c=sum+'0';
}
else{
if(10==sum) c='a';
else if(11==sum) c='b';
else if(12==sum) c='c';
else if(13==sum) c='d';
else if(14==sum) c='e';
else if(15==sum) c='f';
}

}

//一个字符转成8位二进制数
void char_to_bin(char c,int tmp[]){
int n=(int)c;//把ASCII码字符强制转为整数
int cnt=7;
while(n/2){
tmp[cnt--]=n%2;
n/=2;
}
tmp[cnt]=n;
for(int i=0;i<cnt;i++){
tmp[i]=0;
}
}

//一个数转成4位的二进制数
void number_to_bin(int n,int tmp[]){
int cnt=3;
while(n/2){
tmp[cnt--]=n%2;
n/=2;
}
tmp[cnt]=n;
for(int i=0;i<cnt;i++){
tmp[i]=0;
}
}

void circle_left_move(int a[],int step){
int tmp[28];
int cnt=0;
for(int i=step-1;i<28;i++){
tmp[cnt++]=a[i];
}
for(int i=0;i<step;i++){
tmp[cnt++]=a[i];
}
for(int i=0;i<28;i++){
a[i]=tmp[i];
}
}

void make_sub_key(){
int kkey[64];//把16个16进制的数搞成64个二进制的数，并存储在kkey数组中
int kkey_cnt=0;
//秘钥key中的16个16进制数搞成二进制数共64位存到kkey数组中
for(int i=0;i<16;i++){
int tmp[4];
hex_bin(key[i],tmp);
for(int j=0;j<4;j++){
kkey[kkey_cnt++]=tmp[j];
}
}

int K[56];//原秘钥64位搞成56位放在K里面
int K_cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<7;j++){
K[K_cnt++]=kkey[PC_1[i][j]-1];//参照表PC_1来搞，把64位搞成56位秘钥
}
}
int c[17][28],d[17][28];
//64位秘钥搞成56位秘钥后，拆成两半，分别给c[0]和d[0]
for(int i=0;i<28;i++){
c[0][i]=K[i];
d[0][i]=K[i+28];
}

//循环左移16次，得到16对ci,di，存到c[17][28],d[17][28]
for(int i=0;i<16;i++){
int tmp_c[28],tmp_d[28];//暂时存储c[i]和d[i]
for(int j=0;j<28;j++){
tmp_c[j]=c[i][j];
tmp_d[j]=d[i][j];
}
//c[i],d[i]都循环左移left_move_table[i]位
circle_left_move(tmp_c,left_move_table[i]);
circle_left_move(tmp_d,left_move_table[i]);
//c[i],d[i]循环左移后，就变成了c[i+1],d[i+1]
for(int j=0;j<28;j++){
c[i+1][j]=tmp_c[j];
d[i+1][j]=tmp_d[j];
}
}

//对16对cidi56位秘钥用PC_2表转成48位秘钥，存到sub_key数组中
for(int i=0;i<16;i++){
int tmp[56];//暂存c[i+1],d[i+1]组成56位秘钥
for(int j=0;j<28;j++){
tmp[j]=c[i+1][j];
tmp[j+28]=d[i+1][j];
}

//56位转成48位
int cnt=0;
for(int j=0;j<8;j++){
for(int k=0;k<6;k++){
sub_key[i+1][cnt++]=tmp[PC_2[j][k]-1];
}
}
}
}

void exclusive_or(int a[],int b[],int n,int result[]){
for(int i=0;i<n;i++){
if(a[i]==b[i]){
result[i]=0;
}
else{
result[i]=1;
}
}
}

void f(int n,int P_end[32]){
int E[48];
int E_cnt=0;
//Ri通过E_bit_selection_table表转换一下，存到E中
for(int i=0;i<8;i++){
for(int j=0;j<6;j++){
E[E_cnt++]=R[n-1][E_bit_selection_table[i][j]-1];
}
}
int tmp_sub_key[48];//暂存sub_key[n]，一维数组便于操作
for(int i=0;i<48;i++){
tmp_sub_key[i]=sub_key[n][i];
}

int exclusive_or_result[100];//存放异或结果的数组
exclusive_or(E,tmp_sub_key,48,exclusive_or_result);

//把子秘钥sub_key[i]与E异或后的结果exclusive_or_result，48位拆成8份
//每一份有6位，分别对每一份进行S盒转变
int temp_result[8][6];
int temp_result_cnt=0;
for(int i=0;i<48;i++){
if(i%6==0 && i!=0){
temp_result_cnt++;
}
temp_result[temp_result_cnt][i%6]=exclusive_or_result[i];
}

int row;//是S盒中对应的行
int col;//在S盒中对于的列
int S8_end[32];//8个盒搞完之后的结果
int S8_end_cnt=0;//8个S盒过一遍之后的结果计数
for(int i=0;i<8;i++){
row=temp_result[i][0]*2+temp_result[i][5]*1;
col=temp_result[i][1]*8+temp_result[i][2]*4+temp_result[i][3]*2+temp_result[i][4]*1;
int tmp[4];//每一份6位变成4位后暂存tmp数组中
int number=S[i][row][col];//S盒中对应的那个数
number_to_bin(number,tmp);//S盒中对应的那个数转成二进制，暂存在tmp数组
for(int j=0;j<4;j++){
S8_end[S8_end_cnt++]=tmp[j];
}
}
//8个盒子过一遍之后，经P再搞一下,存到P_end里面，即f

int P_cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<4;j++){
P_end[P_cnt++]=S8_end[P[i][j]-1];
}
}
}

void des(){
int M[64];
int M_cnt=0;
//先把8个字符转成64位2进制数，存到M数组中
for(int i=0;i<8;i++){
int tmp[8];//存储每一个1字符对应的8位二进制
char_to_bin(plaintext[i],tmp);
for(int j=0;j<8;j++){
M[M_cnt++]=tmp[j];
}
}
int IP[64];//拿到8字符，转成64位二进制数据块后，安装IP_1表搞一下，搞成新的64位，存到IP数组中
int IP_cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
IP[IP_cnt++]=M[IP_1[i][j]-1];
}
}
//初始化L[0],R[0]为后续f函数准备
for(int i=0;i<32;i++){
L[0][i]=IP[i];
R[0][i]=IP[i+32];
}

//根据Ln=Rn-1,Rn=Ln-1+f(Rn-1,Kn)公式迭代，这里笔者对此公式更加简化如下
//Ln=Rn-1,Rn=f(n-1)
//下面16次循环后，可以求出L16,R16
for(int i=1;i<=16;i++){
for(int j=0;j<32;j++){
L[i][j]=R[i-1][j];//Ln=Rn-1
}
int P_end[32];
f(i,P_end);//Rn=f(n)+Ln-1，这里求出了f,下面异或下产生Rn

int L_tmp[32];
for(int j=0;j<32;j++){
L_tmp[j]=L[i-1][j];//这里开始还是写错了L_tmp[j]的j写成了i，这一点导致了极大的错误，加密和解密求的f全然不同，导致所有的L,R都不同
}

exclusive_or(P_end,L_tmp,32,P_end);
//上面异或的结果就是Rn
for(int j=0;j<32;j++){
R[i][j]=P_end[j];
}//至此，由f(n-1)终于求出了Rn
}
//求出的R16L16暂存在R16L16的数组中
int R16L16[64];
for(int i=0;i<32;i++){
R16L16[i]=R[16][i];
R16L16[i+32]=L[16][i];
}

int goal[64];//R16L16再过一遍IP_2
int goal_cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
goal[goal_cnt++]=R16L16[IP_2[i][j]-1];
}
}

//把得到的64位二进制转成16个16进制数
int tmp_goal[4];
char c;
int ciphertext_cnt=0;
for(int i=0;i<64;i++){
tmp_goal[i%4]=goal[i];
if((i+1)%4==0){
bin_hex(tmp_goal,c);
ciphertext[ciphertext_cnt++]=c;
}
}
}

//对加密之后的密文解密
void decode(){
//61个16进制数的密文先搞成64位，存到tmp1

int tmp1[64];
int tmp1_cnt=0;
for(int i=0;i<16;i++){
int tmp[4];//把一个16进制数转成4位的二进制数,存到tmp中
hex_bin(ciphertext[i],tmp);
for(int j=0;j<4;j++){
tmp1[tmp1_cnt++]=tmp[j];
}
}

//继续解密，先搞出R16L16
tmp1_cnt=0;
int R16L16[64];
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
R16L16[IP_2[i][j]-1]=tmp1[tmp1_cnt++];
}
}

//为了不定义更多的变量，下面求解过程中依然用加密过程中用到的变量
for(int i=0;i<32;i++){
R[16][i]=R16L16[i];
L[16][i]=R16L16[i+32];
}

//经过16次f函数迭代，求L0,R0
for(int i=16;i>=1;i--){
for(int j=0;j<32;j++){
R[i-1][j]=L[i][j];
}

int P_end[32];
f(i,P_end);
int R_tmp[32];
for(int j=0;j<32;j++){
R_tmp[j]=R[i][j];
}
exclusive_or(R_tmp,P_end,32,P_end);
for(int j=0;j<32;j++){
L[i-1][j]=P_end[j];
}

}
int L0R0[64];
for(int i=0;i<32;i++){
L0R0[i]=L[0][i];
L0R0[i+32]=R[0][i];
}

//求出起初的明文64位二进制表示，存到M数组
int M[64];//
int L0R0_cnt=0;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
M[IP_1[i][j]-1]=L0R0[L0R0_cnt++];//这里有问题，看看！！！！！！！！！！！！！！！！！！！！！！！！
}
}

//把64位的M转成8个字符，并输出明文
int tmp_last[8][8];
int tmp_last_cnt=0;
//64位拆成8等份
for(int i=0;i<64;i++){
if(i%8==0 && i!=0){
tmp_last_cnt++;
}
tmp_last[tmp_last_cnt][i%8]=M[i];
}

int mark[8]={128,64,32,16,8,4,2,1};
for(int i=0;i<8;i++){
int x=0;
for(int j=0;j<8;j++){
x+=mark[j]*tmp_last[i][j];
}
plaintext[i]=(char)x;
}
}

void go(){
FILE *fp_plaintext;
FILE *fp_ciphertext;
FILE *fp_decode_text;
FILE *fp_key;

fp_plaintext=fopen("plaintext.txt","r");
fp_ciphertext=fopen("ciphertext.txt","w");
fp_decode_text=fopen("decode_text.txt","w");
fp_key=fopen("key.txt","r");

char c;
init();
int key_cnt=0;
while((c=fgetc(fp_key))!=EOF){
key[key_cnt++]=c;
}
make_sub_key();

int cnt=0;
int sum=0;
while((c=fgetc(fp_plaintext))!=EOF){
plaintext[cnt%8]=c;
cnt++;
sum++;
if(cnt%8==0 && cnt!=0 && sum==8){
des();
for(int i=0;i<8;i++){
fputc(ciphertext[i],fp_ciphertext);
}
decode();//解密
for(int i=0;i<8;i++){
fputc(plaintext[i],fp_decode_text);
}
sum=0;
}
}
if(sum!=0){
for(int i=sum;i<8;i++){
plaintext[i]='0';//不够8位填充0
}
des();
for(int i=0;i<8;i++){
fputc(ciphertext[i],fp_ciphertext);
}
decode();//解密
for(int i=0;i<8;i++){
fputc(plaintext[i],fp_decode_text);
}
}
fclose(fp_plaintext);
fclose(fp_ciphertext);
fclose(fp_decode_text);
fclose(fp_key);
}

//4 实验测试
//笔者将使用上述代码进行实验测试。使用文件读写方式，plaintext.txt文件存放待加密的数据，ciphertext.txt文件存放加密好的数据，key.txt文件存放16位16进制数组成的秘钥，decode_text.txt文件存放经加密再解密的数据。由于本算法实现过程中，加密解密用到的参照表及秘钥完全一样，可以通过对比plaintext.txt文件和decode_text.txt文件内容，如果一致，可以在一定程度上说明算法的正确性。
//（1）plaintext.txt文件中的待加密数据如下：
//I am a student from CCNU.
//I love coding!
//Hello, Wolrd!
//!!!!!!!!!
//（2）key.txt文件中的秘钥如下：
//1234569870abcdef
//（3）程序运行之后，ciphertext.txt文件中的数据如下：