实验环境: DEV C++ 5.11
实验原理:
DES 算法使用的是 Feistel 框架,Feistel 框架的密码结构是用于分组密码 中的一种对称结构,Feistel 框架使用的是对同一处理流程进行多次循环的方式。 DES 算法就是采用的 16 轮循环的加密,当然循环次数越多加密的效果越好,同 时时间成本也会上去,设计者需要考虑这两方面的因素进行密码设计。因为这个 框架是用于处理分组密码的,我们就要了解一下什么是分组密码,分组密码是一 种加解密方案,将输入的明文分组当作一个整体处理,并输出一个等长的密文分组,典型的分组大小为 64 位和 128 位,随着对加密算法安全性能的要求不断提高,分组大小也就会越来越大。DES 算法所采用的分组大小为 64 位分组,所以输入的数据和密钥都是按照 64 位进行处理的,输出的密文也是 64 位一组
实验要求:
使用熟悉的高级语言,编写一段程序,实现凯撒密码
DES 加密算法过程
DES 属于分组密码,明文和密文为 64 位分组。密钥的长度为 64 位,但是密钥的每个第八位设置为奇偶校验位,因此密钥的实际长度为 56 位。
-
初始置换:
使用初始置换表对明文进行置换,这里的置换只是将数据的位置进行变化,得到一个新的数据。初始逆置换表和初始置换表是相互可逆的,就是将原来的数据的位置进行还原。
置换处理:在密码学中置换是指在保持数据不变的情况下,打乱数据的位置顺序的操作称作置换,在 DES 算法中每个置换处理都会按照 相应的置换表进行操作,置换处理在 DES 算法中得到了充分的运用,通过置换处理可以打乱输入数据的顺序,使输入的数据变得面目全非,当然也会造成雪崩效应,因为只要有一个数据位发生变化,就会影响到很多地方。
2.子秘钥生成:
DES 算法子密钥输入长度为 64 位,但是只有 48 位是有效的,所以需要对密钥 K 进行变换得到每一轮所需的子密钥。16 轮迭代就需要 16 个 48位的子密钥来进行加密。
DES 算法子密钥生产比较简单,64 位密钥经过置换选择,只选择其中的 56位,对 56 位密钥同样分为左右 28 位,按照子密钥计算的逻辑表,每一轮进行循环左移运算分别得到新的 56 位,这 56 位再经过第二次置换选择就得到了本轮的子密钥。
然后对S盒的输出结果进行P盒置换
根据流程图可得,最后是左半部分和右半部分合并进行逆初始置换
DES源代码:
#include <stdio.h>
#include<string.h>
#include<math.h>
int get(int r);
void yihuo(int *a, int *b,int num);
void left_move(int s[56], int n);
void exchange(int *a, int *b, int *biao,int n);
void shizhuaner(int *a,int x,int i,int n);
void erzhuanshiliu(int *a,char *b, int n);
void s_box(int a[32],int b[48]);
void round(int r, int a[56], int b[48], int r_a[32], int r_b[48], int l[32], char mi_r[8], char mi_l[8]);
int get(int r) //得到第r轮的移位数
{
int i;
if (r==1||r==2||r==9||r==16) i=1;
else i=2;
return i;
}
void yihuo(int *a, int *b,int num) //异或
{
int i;
for (i=0;i<num;i++)
{
if (a[i]==b[i]) a[i]=0;
else
a[i]=1;
}
}
void left_move(int s[56], int n) //左移
{
int i;
for (i=0;i<=28-n;i++)
{
s[i]=s[(i+n)%28];
}
for(i=28;i<=56-n;i++)
{
s[i]=s[(i+n)%56];
}
}
void exchange(int *a, int *b, int *biao,int n) //置换
{
int i,loc;
for (i=0;i<n;i++)
{
loc=biao[i];
b[i]=a[loc-1];
}
return;
}
void shizhuaner(int *a,int x,int i,int n)
// a是存放二进制的数组,x是需要进行转换的十进制数,i是第i个十进制数,n是数组大小
{
int j;n=n/8;j=n-1;
do{
a[i*n+j]=x%2;
x=x/2;
j--;
} while(x!=0);
while (j>=0)
{
a[i*n+j]=0;
j--;
}
return;
}
void erzhuanshiliu(int *a,char *b, int n)
// a是二进制数组,b是存放十六进制的数组,n是二进制数组的大小
{
int i,j;
n=n/4;
for(i=0;i<n;i++)
{
j=8*a[4*i]+4*a[4*i+1]+2*a[4*i+2]+a[4*i+3];
if(j>=10){
if(j==10) b[i]='a';
else if(j==11) b[i]='b';
else if(j==12) b[i]='c';
else if(j==13) b[i]='d';
else if(j==14) b[i]='e';
else if(j==15) b[i]='f';
}
else
{
j=j+48;
b[i]=(char)j;
}
}
return;
}
void s_box(int a[32],int b[48]) //S盒
{
int i,r,c,s;
int s1[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 } },
s2[4][16] = { { 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[4][16] = { { 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[4][16] = { { 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, 3 },{ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } },
s5[4][16] = { { 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[4][16] = { { 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][16] = { { 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[4][16] = { { 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 } };
for (i = 0; i < 8; i++)
{
r = 2*b[6*i]+b[6*i+5];
c = 8*b[6*i+1]+4*b[6*i+2]+2*b[6*i+3]+b[6*i+4];
switch (i)
{
case 0:s = s1[r][c]; break;
case 1:s = s2[r][c]; break;
case 2:s = s3[r][c]; break;
case 3:s = s4[r][c]; break;
case 4:s = s5[r][c]; break;
case 5:s = s6[r][c]; break;
case 6:s = s7[r][c]; break;
case 7:s = s8[r][c]; break;
}
shizhuaner(a,s,i,32);
}
}
void round(int r, int a[56], int b[48], int r_a[32], int r_b[48], int l[32], char mi_r[8], char mi_l[8])
{
int i, n, r1[32],r2[32]; //r1,r2为中间数组
int zhihuan2[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 }; //置换2
int e[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 }; //E盒
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 }; //P盒
printf("这是第%d轮密文:\n", r);
n = get(r); left_move(a, n); exchange(a, b, zhihuan2, 48);
exchange(r_a,r_b,e,48); yihuo(r_b, b,48); s_box(r1,r_b); exchange(r1,r2,P,32);
for (i=0;i<32;i++) r1[i] = r2[i];
yihuo(r1,l,32);
for (i=0;i<32;i++) l[i] = r_a[i]; //准备下次循环的L
for (i=0;i<32;i++) r_a[i] = r1[i]; //准备下次循环的R
erzhuanshiliu(r_a,mi_r,32);
erzhuanshiliu(l,mi_l, 32);
for (i=0;i<8;i++) printf("%c ",mi_r[i]); //第r轮R部分的密文
for (i=0;i<8;i++) printf("%c ",mi_l[i]); //第r轮L部分的密文
printf("\n\n");
return;
}
int main()
{
char a[8]; //初始明文
char b[8]; //初始密钥
int m_a[64],m_b[64]; //IP置换前后的明文
int s_a[64],s_b[56]; //置换1前后的二进制密钥
int r; //轮数
int s_c[48]; //置换2后的数组
int r_a[32],r_b[48]; //E扩展前后的m_b的右半部分明文
int l[32]; //m_b的左半部分
char mi_r[8],mi_l[8]; //存储密文的十六进制
int mi1[16],mi2[16]; //IP_1置换前后的密文
char miwen[16]; //最终密文
int i;
int zhihuan1[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 }; //置换1
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 }; //IP置换
int IP_1[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 }; //IP_1置换
printf("*---------------DES加密--------------\n\n");
printf("请输入需要加密的明文:\n");
for (i=0;i<8;i++)
{
scanf("%c",&a[i]);
shizhuaner(m_a,(int)a[i],i,64);
}
printf("\n请输入加密的密钥:\n");
for (i=0;i<8;i++)
{
scanf("%c", &b[i]);
shizhuaner(s_a,(int)b[i],i,64);
}
exchange(m_a,m_b,IP, 64);
for(i=0;i<32;i++)
l[i]=m_b[i];
for(i=32;i<64;i++)
r_a[i-32]=m_b[i];
exchange(s_a,s_b,zhihuan1,56);
for (r=1;r<=16;r++)
round(r,s_b,s_c,r_a,r_b,l,mi_r,mi_l);
for(i=0;i<64;i++) //将密文R的部分与密文L的部分合一起
{
mi1[i]=r_a[i];
if(i>=32) mi1[i]=l[i-32];
}
exchange(mi1,mi2,IP_1,64);
erzhuanshiliu(mi2,miwen, 64); //二进制转换成十六进制,得到最终密文
printf("\n\n");
printf("##########这是最终密文:##########\n");
for (i=0;i<16;i++)
printf("%c ", miwen[i]);
printf("\n\n\n\n");
return 0;
}