#include<bits/stdc++.h>
using namespace std;
#define ENCODE true
#define DECODE false
const int
//初始置换函数IP
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
},
//末置换
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
},
//密钥每次移动位数
KM[16] ={1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 ,1 , 2 , 2 , 2 , 2 , 2 , 2 , 1},
//密钥置换PC-1
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
},
//密钥的压缩置换PC-2
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
},
//S盒
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}
}
},
//扩展置换E盒
E_BOX[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
},
//P盒
P_BOX[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
};
bool KEY[16][48]; //16个子密钥
void Permutation(bool x[],int length,const int BOX[]) //置换函数,参数:待置换数据,长度,置换盒子
{
bool *tmp=new bool[length];
for(int i=0;i<length;++i)
tmp[i]=x[BOX[i]-1];
for(int i=0;i<length;++i)
x[i]=tmp[i];
}
void GetKey(bool key[64]) //生成子密钥
{
bool C[60],D[60]; //开两倍大小的数组是为了方便实现循环移位
int i,j,st;
memset(KEY,0,sizeof(KEY));
for(i = 0; i < 28; ++i) //PC-1置换,得到28位的C0,D0
{
C[i+28] = C[i] = key[PC1[i]-1];
D[i+28] = D[i] = key[PC1[i+28]-1];
}
st = 0; //累计移动位数(C和D不变,为基准,加上st实现多次移位)
for(i = 0; i < 16; ++i) //16次置换,得到16个子密钥
{
st += KM[i];
for(j = 0; j < 48; ++j)
KEY[i][j] = (PC2[j] < 28)?C[PC2[j] + st - 1]:D[PC2[j] - 29 + st];
}
}
void Work(bool L[32],bool R[32],bool KEY[48],int cnt) //一轮DES
{
bool X[48],RES[32];
memset(RES,0,sizeof(RES));
memset(X,0,sizeof(X));
int i,j,a,b,st,tmp;
for(i = 0; i < 48; ++i) //R扩展置换得到48位,和子密钥异或
X[i] = R[E_BOX[i]-1] ^ KEY[i];
//将异或得到的结果压缩置换成32位
for(i = 0; i < 8; ++i) //分为8个6位的块
{
st = i * 6; //每个块的起始位置
a = (X[st] << 1) + X[st + 5]; //取第1位和第6位(2进制),构成行数
//中间4位构成列数
b = (X[st + 1] << 3) + (X[st + 2] << 2) + (X[st + 3] << 1) + X[st + 4];
tmp = S_BOX[i][a][b]; //查找S盒
st = i * 4; //保存结果的数组当前存放位置的开始位置
for(j = 0; j < 4; ++j) //拼接每次的tmp(转为4位二进制)到RES中
RES[st + (3 - j)] |= (tmp >> j)&1;
}
Permutation(RES,32,P_BOX);
for(i=0;i<32;++i)
L[i] ^= RES[i];
if (cnt == 15) return ; //注意这里!!!!!!!!
//最后一轮不需要交换L和R,原因是最后拼接为64位的时候
//是把L作为低32位,R作为高32位的!!!!
for(i=0;i<32;++i)
swap(L[i],R[i]);
}
void DES(char txt[10],char enc[10],bool flag) //DES函数,加解密共用,参数为64位明文/密文、和存放结果的数组、加解密标记
{
int i,j;
bool L[32],R[32];
bool pt[64];
for(i = 0; i < 8; ++i)
for(j = 7; j >= 0; --j) //8位字符转换为64位2进制
pt[i * 8 + (7 - j)] = (txt[i] >> j) & 1;
Permutation(pt,64,IP); //初始置换
for(i = 0; i < 32; ++i) //拆分为两个32位
L[i] = pt[i],R[i] = pt[i + 32];
if(flag==ENCODE) //加密
{
for(i = 0; i < 16; ++i) //16轮迭代
Work(L,R,KEY[i],i);
}
else //解密
{
for(i = 0; i < 16; ++i) //16轮迭代
Work(L,R,KEY[15-i],i);
}
for(i = 0; i < 32; ++i) //拼接得到64位,注意,这里的L实际上是R16,R为R15,即L16
pt[i] = L[i],pt[i + 32] = R[i];
Permutation(pt,64,FP); //末置换
for(i = 0; i < 8; ++i)
for(j = 7; j >= 0; --j)
enc[i] |= pt[i * 8 + (7 - j)] << j;
}
char Fpt[1005],Fct[1005],key[1005];
void solve(bool flag)
{
int tmp,i,j;
bool sk[64];
char txt[10],res[10];
FILE *R,*W;
for(i = 0; i < 8; ++i)
for(j = 7; j >= 0; --j)
sk[i * 8 + (7 - j)] = (key[i] >> j) & 1; //密钥转为64位2进制
GetKey(sk);
R = flag==ENCODE?fopen(Fpt,"r"):fopen(Fct,"r");
W = flag==ENCODE?fopen(Fct,"w"):fopen(Fpt,"w");
if(R==NULL||W==NULL) {puts("文件打开失败!"); return;}
flag==ENCODE?puts("加密结果如下:"):puts("解密结果如下:");
while((tmp = fread(txt,sizeof(txt[0]),8,R))) //每次读取8个字符到txt中
{
for(i = tmp; i < 8; ++i) txt[i] = 0; //不满8位,在末尾补0
memset(res,0,sizeof(res));
DES(txt,res,flag);
fwrite(res,sizeof(res[0]),8,W);
printf("%s",res);
}
puts("");
fclose(W);
fclose(R);
}
int main()
{
int ch;
while(true)
{
puts("请选择:1.加密 2.解密");
scanf("%d",&ch);
printf("请输入存放明文的文件名(含后缀):");
scanf("%s",Fpt);
printf("请输入存放密文的文件名(含后缀):");
scanf("%s",Fct);
printf("请输入密钥:");
scanf("%s",key);
int L=strlen(key);
if(L>8) {puts("密钥长度不符合要求");continue;}
else if(L<8) //密钥长度不足,后面添0
{
for(int i=L;i<8;++i) key[i]=0;
}
if (ch==1) solve(ENCODE);
else if (ch==2) solve(DECODE);
else break;
}
return 0;
}
DES
最新推荐文章于 2024-11-14 17:25:50 发布