DES加密算法
2022/7/12 14:23:21
本文主要是介绍DES加密算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- DES加密算法
- 1.0 DES简介
- 2.0 算法大致流程
- 3.0 原理和实现
- 3.1 IP置换
- 3.2 轮函数
- E扩展
- 轮密钥异或
- S盒压缩
- P置换
- 3.3 IP逆置换
- 3.4 密钥生成
- 4.0 解密过程
- 5.0 完整的轮子(网上嫖的)
DES加密算法
1.0 DES简介
DES算法为密码体制中的对称密码体制,又被称为美国数据加密标准。
DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的基本上是同一个算法。其密钥长64位,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1),分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。
2.0 算法大致流程
大概流程如下
具体一些的如下
3.0 原理和实现
由第二节的流程图,我们大概知道了,DES加密算法大概流程为
IP置换 => 16轮迭代 =>IP逆置换 三个步骤
其中涉及到F轮函数的设计以及密钥生成方法,下面将分别介绍。
3.1 IP置换
将64位二进制明文按照下表进行置换,经过置换后,明文的第i
位变成了原来的IP_1[i]
位。
置换之后再把64位明文分为L0和R0两部分,各32位。
代码实现:
bool data[65],L_0[65],R_0[65]; // 明文以及打乱之后分开的L0和R0 int IP_1[65] = // IP初始置换表 { 0, 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_Init_Trans() { bool tmp[65]; for(int i=1;i<=64;i++)tmp[i] = data[i]; for(int i=1;i<=64;i++)data[i] = tmp[IP_0[i]]; for(int i=1;i<=32;i++)L_0[i] = data[i],R_0[i] = data[i + 32]; }
3.2 轮函数
轮函数分为四步:
E扩展
扩展置置换目标是IP置换后获得的右半部分R_0,将32位输入扩展为48位(分为4位×8组)输出。
由流程图可知这个函数只对R_0用
,而L_0是直接赋值的。
E扩展置换表为
可以发现,这个置换表的原理就是,把32bit数据分成8组,每组4bit,把每个4bit数据最左边添加上其上一组4bit数据的第四位,每个4bit数据最右边添加上其下一组数据的第一位,其中第一组和最后一组是相邻的。这样就把8 * 4bit = 32bit
数据转变成了8 * 6bit = 32bit
数据。
轮密钥异或
扩展置换之后,右半部分数据R_0变为48位,与轮密钥进行异或,这里只需要知道轮密钥是由密钥生成函数产生的,其长度也为48bit,密钥生成函数后面会提到。
S盒压缩
将异或之后的48位R_0分成8组,每组长度为6bit,将它们分别输入到S_1到S_8这8个盒中,每个盒产生4位输出,最后将输出拼接成4 * 8 = 32bit
数据。
具体方法为:
把6bit数据首位2位拿出来,中间4位拿出来,拼接转化成10进制数,假设分别为a,b,输出就是第S_i盒的第a行第b列。再把这个十进制数转化为4位2进制数,就实现了S盒的压缩功能。
P置换
最后再进行一次P盒置换
代码实现:
int E[33] = { 0, 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} } }; int P[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 }; int E_R0[50]; void E_Extent() { for(int i=1;i<=48;i++) E_R0[i] = R0[E[i]]; /*for(int i=0;i<8;i++) { if(i == 0)E_R0[i + 1] = R0[32],E_R0[i + 6] = R0[(i + 1) * 4 + 1]; else if(i == 7)E_R0[i * 6 + 1] = R0[(i - 1) * 4 + 4],E_R0[i * 6 + 6] = R0[1]; // 特判一下 else E_R0[i * 6 + 1] = R0[(i - 1) * 4 + 4], E_R0[i * 6 + 6] = R0[(i + 1) * 4 + 1]; for(int j=2;j<=5;j++) E_R0[i * 6 + j] = R0[i * 4 + j - 1]; }*/ } void Key_Xor() { for(int i=1;i<=48;i++)E_R0[i] ^= K0[i]; } void S_Compact() { for(int i=0;i<8;i++) { int a = E_R0[i * 6 + 1] << 1 + E_R0[i * 6 + 6]; int b = E_R0[i * 6 + 2] << 3 + E_R0[i * 6 + 3] << 2 + E_R0[i * 6 + 3] << 1 + E_R0[i * 6 + 4]; int c = S[i][a][b]; for(int j=4;j>=1;j--) { R0[i * 4 + j] = c % 2; c /= 2; } } } void P_Rep() { int tmp[33]; for(int i=1;i<=32;i++)tmp[i] = R0[i]; for(int i=1;i<=32;i++)R0[i] = tmp[P[i]]; } void f() { E_Extent(); Key_Xor(); S_Compact(); P_Rep(); }
3.3 IP逆置换
16轮迭代后将L16与R16合并,形成64位二进制,然后按照下表进行逆初始置换,得到最终的64位密文。
代码实现:
int IP2[65] = { 0, 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=1;i=32;i++)tmp[i] = L16[i]; for(int i=33;i<=64;i++)tmp[i] = R16[i - 32]; for(int i=1;i<=64;i++)data[i] = tmp[IP2[i]]; }
3.4 密钥生成
之前只介绍了关于密钥的使用,但是第k轮的密钥是如何获得的并没有说明。
密钥生成流程如下
将初始的64位密钥按顺序编号,然后填充为8*8矩阵,最后一列作为奇偶校验位(也就是8,16,24,32,40,48,56和64这8位),其他的56位组成初始56位密钥。
随后将初始56位密钥按下图的置换表进行置换,打乱密钥顺序
发现以及从64位变成了56位,我们把这56位分成两份Ci和Di,每份28位,按下方的移位次数表进行移位
每一轮移位以后我们都可以将C和D拼起来获得一个56位密钥Ki,再按照下表对密钥进行压缩,从56位变成48位,就可以用到轮函数的计算中了。
代码实现:
int Key[65], Key_Trans[65], C[65], D[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] = // 密钥初始置换表 { 0, 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[50] = // 第二次压缩置换表 { 0, 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=1;i<=56;i++)Key_trans[i] = Key[Key_Init[i]]; for (int i=0;i<=28;i++)C[i] = Key_trans[i]; for (int i=29;i<=56;i++)D[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 = C[1], tmp_2 = D[1]; for (j=1;j<=27;j++)C[j] = C[j + 1], D[j] = D[j + 1]; C[28] = tmp_1, D[28] = tmp_2; } else // 左移两位 { tmp_1 = C[1], tmp_2 = C[2], tmp_3 = D[1], tmp_4 = D[2]; for (int j=1;j<=26;j++)C[j] = C[j + 2], D[j] = D[j + 2]; C[26] = tmp_1, C[27] = tmp_2, D[26] = tmp_3, D[27] = tmp_4; } } for (int i=1;i<=28;i++) Key_trans[i] = C[i]; for (int i=29;i<=56;i++) Key_trans[i] = D[i - 28]; // 拼起来 for (int i=1;i<=48;i++) Key[i] = Key_trans[Key_comp[i]]; //第二次置换 }
4.0 解密过程
DES算法的解密和加密是一个原理,算法也基本类似,只有少数地方不同
-
若加密时子密钥的使用顺序是K1, K2...K16,那么解密时顺序就是K16, K15...K1
-
加密生成密钥时是循环左移,解密生成密钥时是循环右移
5.0 完整的轮子(网上嫖的)
//经过上述对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 char_to_bin(char c,int tmp[]);//把一个ADCII码字符转成2进制8位存储到tmp 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文件中的数据如下: //5ff508a138d8a0f826ae29f6c9b80ad4fefdebf88062bd1574f648693a63c2e5 //(4)程序运行之后,decode_text.txt文件内容如下: //I am a student from CCNU. //I love coding! //Hello, Wolrd! //!!!!!!!!! //对比plaintext.txt文件和decode_text.txt文件内容,完全一致,这表明原始数据和加密后再解密的数据一致,可以在一定程度上说明算法的正确性。
这篇关于DES加密算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-22[开源]10.3K+ Star!轻量强大的开源运维平台,超赞!
- 2024-11-21Flutter基础教程:新手入门指南
- 2024-11-21Flutter跨平台教程:新手入门详解
- 2024-11-21Flutter跨平台教程:新手入门与实践指南
- 2024-11-21Flutter列表组件教程:初学者指南
- 2024-11-21Flutter列表组件教程:新手入门指南
- 2024-11-21Flutter入门教程:初学者必看指南
- 2024-11-21Flutter入门教程:从零开始的Flutter开发指南
- 2024-11-21Flutter升级教程:新手必读的升级指南
- 2024-11-21Flutter升级教程:轻松掌握Flutter版本更新