本项目由之前课设成果整理改编上传,供大家交流分享。
其中内容包括代码等大部分为我自己的原创,基于开源的互联网精神,也会分享给大家。
C语言实现DES加密:
#include <stdio.h>
#include<string.h>
#include <time.h>
#include <stdlib.h>
//IP初始置换表
int IPS_Table[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
};
//IP-1逆初始置换表
int IPE_Table[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
};
//PC1密钥通路初始置换
int PC1_Table[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
};
//PC2密钥通路输出置换
int PC2_Table[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盒
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
};
//E盒扩展
int E_Table[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
};
//f函数最后的P置换
int P_Table[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
};
//将二进制字符转换为二进制值
void BinChar2Value(char *source,char *dest)
{
int i=0;
for(i=0;i<strlen(source);i++)
{
if(source[i]=='0')
dest[i]=0;
if(source[i]=='1')
dest[i]=1;
}
}
//将16进制字符转换为二进制值
void Hex2Bin(char source[],char dest[],int len)
{
int i=0;
char temp[64]={0};
char Dict[17][5] =
{
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111",
};
for(i=0;i<len;i++){
int n = 16;
if (source[i] >='a'&&source[i]<='f')
n=source[i]-'a'+10;
if (source[i]>='A'&& source[i]<='F')
n=source[i]-'A'+10;
if (source[i]>='0'&& source[i]<='9')
n=source[i]-'0';
memcpy(&temp[i*4],Dict[n],4);
BinChar2Value(temp,dest);
}
return;
}
//将十进制值转换为二进制值
void Dec2Bin(int num,char *dest)
{
char temp[4];
char Dict[17][5] =
{
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111",
};
memcpy(temp,Dict[num],4);
BinChar2Value(temp,dest);
}
//将二进制值转换为16进制字符
void Bin2Hex(char Bin[64],char Hex[16])
{
int i;
for(i=0;i<16;i++)
{
Hex[i]=Bin[0+4*i]*8+Bin[1+4*i]*4+Bin[2+4*i]*2+Bin[3+4*i];
if(Hex[i]<10)
Hex[i]=Hex[i]+'0';
else Hex[i]=Hex[i]-10+'a';
}
}
//按位异或运算
void Xor(char InA[],char InB[],int len)
{
int i=0;
for(i=0;i<len;i++)
{
InA[i]=InA[i]^InB[i];
}
}
//DES初始和结束时的IP置换运算,通过改变输入的IP表进行选择
void IP_trans(char input[64],char output[64],int table[64])
{
int i=0;
for(i=0;i<64;i++)
{
output[i]=input[table[i]-1];
}
}
//PC-1置换运算
void PC_1(char input[64],char output[56],int table[56])
{
int i=0;
for(i=0;i<56;i++)
{
output[i]=input[table[i]-1];
}
}
//PC-2置换运算
void PC_2(char input[56],char output[48],int table[48])
{
int i=0;
for(i=0;i<48;i++)
{
output[i]=input[table[i]-1];
}
}
//循环左移函数,为生成轮密钥服务
void Left_shift(char *keyin)
{
char temp;
temp=keyin[0];
memmove(keyin,keyin+1,27);
keyin[27]=temp;
}
//轮密钥生成函数
void KS(char Keyin[64],char Keyround[16][48])
{
int i=0;
char temp[56]; //只定义一个存储密钥,左右通过指针区分
char PC1out[56]={0};
char *keyL=&temp[0],*keyR=&temp[28];
PC_1(Keyin,PC1out,PC1_Table);
memcpy(keyL,PC1out,28);
memcpy(keyR,PC1out+28,28);
for(i=0;i<16;i++)
{
if((i==0)||(i==1)||(i==8)||(i==15)) //不同轮次,左移次数不同
{
Left_shift(keyL);
Left_shift(keyR);
}
else
{
Left_shift(keyL);
Left_shift(keyL);
Left_shift(keyR);
Left_shift(keyR);
}
PC_2(temp,Keyround[i],PC2_Table);
}
}
//E扩展
void E(char input[32],char output[48],int table[48])
{
int i=0;
for(i=0;i<48;i++)
{
output[i]=input[table[i]-1];
}
}
//S盒函数
void S(char input[48],char output[32],int table[8][4][16])
{
int i,X,Y;
char temp[4]={0};
for(i=0,Y=0,X=0;i<8;i++)
{
X=(input[1+6*i]<<3)+(input[2+6*i]<<2)+(input[3+6*i]<<1)+input[4+6*i];
Y=(input[0+6*i]<<1)+input[5+6*i];
Dec2Bin(table[i][Y][X],temp); //根据每输入的6位的值,计算出S盒表的坐标,取出十进制值,再转换为二进制值
memcpy(output+4*i,temp,4);
}
}
//P置换
void P(char input[32],char output[32],int table[32])
{
int i=0;
for(i=0;i<32;i++)
{
output[i]=input[table[i]-1];
}
}
//f函数
void F_fun(char input[32],char Roundkey[48],char F_out[32])
{
char E_out[48]={0};
char S_out[32]={0};
E(input,E_out,E_Table);
Xor(E_out,Roundkey,48);
S(E_out,S_out,S_Box);
P(S_out,F_out,P_Table);
}
//DES运算的函数
void Des_fun(char datain[64],char key[64],char dataout[64])
{
int i;
char IPS_out[64]={0};
char RoundKey[16][48];
char temp[64]={0}; //只定义一个数组存储,L,R通过指针改变其值
char *L=&temp[0],*R=&temp[32];
char F_out[32]={0};
IP_trans(datain,IPS_out,IPS_Table); //初始IP置换
memcpy(L,IPS_out,32); //分出左右
memcpy(R,IPS_out+32,32);
KS(key, RoundKey); //生成轮密钥,并存储
for(i=0;i<16;i++)
{
F_fun(R,RoundKey[i],F_out); //循环执行16轮
Xor(F_out,L,32);
memcpy(L,R,32);
memcpy(R,F_out,32);
}
memcpy(R, L, 32);
memcpy(L, F_out, 32); //注意:最后结束循环后,左右不需交换了(再换一次换回来)
IP_trans(temp,dataout,IPE_Table);
}
void main()
{
int i;
char plaintext[17]; //plaintext和key必须17位,因为strcpy复制会把最后的结束位复制过来,导致溢出
char key[17];
char ciphertext[17]={0}; //此初始赋0,方便最后puts输出结束
char plaintext_bin[64];
char key_bin[64];
char ciphertext_bin[64];
clock_t start, finish; //计时变量
double total_time;
start = clock();
//去掉下方注释可改变为手动输入
/*printf("输入明文(16位hex):\n");
gets(plaintext);
printf("输入密匙(16位hex):\n");
gets(key); */
strcpy(plaintext,"123456abcd132536");
strcpy(key,"aabb09182736ccdd");
Hex2Bin(plaintext,plaintext_bin,16); //将接收到的字符串转换为二进制值
Hex2Bin(key,key_bin,16);
start = clock();
for (i = 0; i < 10000;i++) //循环10000次,计算平均时间
Des_fun(plaintext_bin, key_bin, ciphertext_bin);
finish = clock();
Bin2Hex(ciphertext_bin,ciphertext); //将加密信息转换回16进制字符串以便显示
total_time = (double)(finish - start)/ CLOCKS_PER_SEC;
printf("Ciphertext:\n");
puts(ciphertext); //显示密文
printf( "%f seconds\n",total_time); //显示所用时间
system("pause");
}
此处代码参考了网上的代码设计,但是我找到的代码无法正常使用,我又重新编写测试解决了一系列问题。
此导图是我为C语言程序编写的导图,也能大概看出DES加密的原理。
硬件上提供了一版DES的Verilog代码可以通过FPGA平台运行。
链接:https://pan.baidu.com/s/1YY8qO1J_QPC0YpRh415cYw
提取码:siwu
软硬件速率对比
C语言软件运行情况:
环境:C语言编译 gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project
运行 WIN10教育版 版本号1803 处理器:Intel® Core™ i7-7700HQ CPU @ 2.80GHz
因为软件运行受到计算机当前状态的波动,故截取了三次结果,求平均值
以下都是每10000次64位DES加密所需时间。
经过计算平均每秒可计算46012次,即加密速率2944768 bit/s。
接下来我更换了环境,在老师提供的Linux虚拟机上运行
将代码通过本地分享到虚拟机中,拷贝到虚拟机内的目录里,用gcc编译,并同样运行三次,求得平均时间。
经计算每秒可计算27272次,即1745408 bit/s
此时软件运行速率比Win10下要慢,个人仍为可能是虚拟机设置上只调用了部分电脑的硬件,没有充分发挥硬件的性能。
硬件综合结果:
时钟周期为3.9ns,delay设置为0.3,此时可slack可以符合,且时钟周期最小
以DES硬件极限16周期加密一次计算,平均62.4ns一次,即每秒16025641次,加密速率1025641024 bit/s。
由此可见,硬件加密的速率是软件的3个数量级以上。
附:面积报告