DES加解密过程及其C语言实现

1 DES加解密原理

DES算法为密码体制中的对称密码体制,又被称为美国数据加密标准,是1972年美国IBM公司研制的对称密码体制加密算法。明文按64位进行分组,密钥长64位,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1)分组后的明文组和56位的密钥按位替代或交换的方法形成密文组的加密方法。其入口参数有三个:key、data、mode。key为加密解密使用的密钥,data为加密解密的数据,mode为其工作模式。当模式为加密模式时,明文按照64位进行分组,形成明文组,key用于对数据加密,当模式为解密模式时,key用于对数据解密。实际运用中,密钥只用到了64位中的56位,这样才具有高的安全性。

1.1 DES算法总体描述及流程图

DES是一个分组加密算法,它以64位为分组对数据加密。64位一组的明文从算法的一端输入,64位的密文从另一段输出。它是一个对称算法:加密和解密用的是同一个算法。密钥通常表示为64位的数,但每个第8位都用作奇偶校验,可以忽略,所以密钥长度为56位。密钥可以是任意的56位的数,且可在任意的时候改变。
对于任意的加密方案,总有两个输入:明文和密钥。DES的明文长为64位,密钥长为56位。明文的处理一般经过三个阶段:首先,64位的明文经过初始置换(IP)而被重新排列。然后经历16轮相同函数的作用,每轮作用都有置换和代替。最后一轮迭代的输出有64位,它是输入明文和密钥的函数。其左半部分和右半部分互换产生预输出。最后预输出再被与初始置换(IP)互逆的置换产生64位的密文。
DES算法只不过是加密的两个基本技术——混乱和扩散的组合,即先代替后置换,它基于密钥作用于明文,这是一轮(round),DES在明文分组上实施16轮相同的组合技术。如下图所示:
在这里插入图片描述
图1 DES算法总体描述
DES使得用相同的函数来加密或解密每个分组成为可能,二者唯一的不同就是密钥的次序相反。

1.2 DES加解密算法原理

DES对64位明文分组进行操作。通过一个初始置换,将明文分组分成左半部分和右半部分,各32位长。然后进行16轮完全相同的运算,这些运算被称为函数 f,在运算过程中数据与密钥结合。经过16轮后,左、右半部分合在一起经过一个末置换(初始置换的逆置换),算法就完成了。
在每一轮中,密钥位移位,然后再从密钥的56位中选出48位。通过一个扩展置换将数据的右半部分扩展成48位,并通过一个异或操作与48位密钥结合,通过 8个S盒将这48位替代成新的32位数据,再将其置换一次。这四步运算构成了函数f。然后,通过另一个异或运算,函数f的输出与左半部分结合,其结果即成为新的左半部分。将该操作重复16次,便实现了DES的16轮运算。一轮DES如下图所示:
在这里插入图片描述
图2 DES算法一轮迭代的过程

假设Bi是第i次迭代的结果,Li和Ri是Bi的左半部分和右半部分,Ki是第i轮的48位密钥,且f是实现代替、置换及密钥异或等运算的函数,那么每一轮就是:
Li=Ri-1
Ri=Li-1⊕f(Ri-1,Ki)

2 程序代码
#include <iostream> 
#include <fstream> 
using namespace std;

const static char 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  };  
	

const static char fp[] = {                  //末置换      
	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 };

const static char sbox[8][64] = {            //s_box   
/* 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 }; 


const static char rar[] = {    //压缩置换    
	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 };


const static char ei[] = {    //扩展置换   
	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 

}; 
 const static char Pzh[]={     //P置换   
	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 };

const static char Keyrar[]={     
	57, 49, 41, 33, 25, 17,  9,  
	1, 58, 50, 42, 34, 26, 18,   
	10,  2, 59, 51, 43, 35, 27,   
	9, 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 };

bool key[16][48]={0},/*rekey[16][48],*/ 
char key_in[8];  
void ByteToBit(bool *Out,char *In,int bits)  //字节到位的转换
 {   int i;   
for(i=0;i<bits;i++)   
 Out[i]=(In[i/8]>>(i%8))&1; }  
void BitToByte(char *Out,bool *In,int bits)   //位到字节转换 
{   for(int i=0;i<bits/8;i++)  
 Out[i]=0;   for(i=0;i<bits;i++)   
 Out[i/8]|=In[i]<<(i%8);   // "|="组合了位操作符和赋值操作符的功能
 }
void Xor(bool *InA,const bool *InB,int len)    //按位异或
 {   for(int i=0;i<len;i++)  
 InA[i]^=InB[i]; } 
 void keyfc(char *In)              //获取密钥函数 
 {
int i,j=0,mov,k;   
bool key0[56],temp,keyin[64];  
ByteToBit(keyin,In,64);           //字节到位的转换   
for(i=0;i<56;i++)                      //密钥压缩为56位  
 key0[i]=keyin[Keyrar[i]-1];  
 for(i=0;i<16;i++)       //16轮密钥产生 
 {    if(i==0||i==1||i==8||i==15)   
 mov=1;  
 else     mov=2;   
 for(k=0;k<mov;k++)    //分左右两块循环左移  
 {     for(int m=0;m<8;m++)  
 {      temp=key0[m*7];     
 for(j=m*7;j<m*7+7;j++)     
	 key0[j]=key0[j+1];     
 key0[m*7+6]=temp;    }     
 temp=key0[0];   
 for(m=0;m<27;m++)    
	 key0[m]=key0[m+1];   
 key0[27]=temp;   
 temp=key0[28];    
 for(m=28;m<55;m++)    
	 key0[m]=key0[m+1];   
 key0[55]=temp;   }   
 for(j=0;j<48;j++)         //压缩置换并储存     
	 key[i][j]=key0[rar[j]-1];  } } 


void DES(char Out[8],char In[8],bool MS)//加密核心程序,ms=0时加密,反之解密
 {   bool MW[64],tmp[32],PMW[64]; bool kzmw[48],keytem[48],ss[32]; 
 int hang,lie;  
 ByteToBit(PMW,In,64); 
 for(int j=0;j<64;j++)
 {    MW[j]=PMW[ip[j]-1];          //初始置换 
 }

bool *Li=&MW[0],*Ri=&MW[32];   
for(int i=0;i<48;i++)       //右明文扩展置换   
kzmw[i]=Ri[ei[i]-1];       
if(MS==0)          //DES加密过程  
{    for(int lun=0;lun<16;lun++)   
{     for(i=0;i<32;i++)     
ss[i]=Ri[i];    
 for(i=0;i<48;i++)       //右明文扩展置换  
kzmw[i]=Ri[ei[i]-1];       //注意指针  
 for(i=0;i<48;i++)     
	 keytem[i]=key[lun][i];      //轮密钥   
 Xor(kzmw,keytem,48);

/*S盒置换*/    
 for(i=0;i<8;i++)   
 {      
	 hang=kzmw[i*6]*2+kzmw[i*6+5];  
	 lie =kzmw[i*6+1]*8+kzmw[i*6+2]*4+kzmw[i*6+3]*2+kzmw[i*6+4];   
	 tmp[i*4+3]=sbox[i][(hang+1)*16+lie]%2;    
	 tmp[i*4+2]=(sbox[i][(hang+1)*16+lie]/2)%2;   
	 tmp[i*4+1]=(sbox[i][(hang+1)*16+lie]/4)%2;  
	 tmp[i*4]=(sbox[i][(hang+1)*16+lie]/8)%2;    }
for(int i=0;i<32;i++)  //P置换       
Ri[i]=tmp[Pzh[i]-1];    
 Xor(Ri,Li,32);    //异或   
 for(i=0;i<32;i++)  //交换左右明文   
 {      Li[i]=ss[i];    }   }
for(i=0;i<32;i++)  
 {    
	tmp[i]=Li[i];    
	Li[i]=Ri[i];    
	Ri[i]=tmp[i];   } 
   for(i=0;i<64;i++)   
	   PMW[i]=MW[fp[i]-1];   
   BitToByte(Out,PMW,64);  //位到字节的转换  
 }  
 else          //DES解密过程
  {
for(int lun=15;lun>=0;lun--)   {   
	for(i=0;i<32;i++)    
ss[i]=Ri[i];    for(int i=0;i<48;i++)       //右明文扩展置换   
kzmw[i]=Ri[ei[i]-1];       //注意指针   
for(i=0;i<48;i++)   
keytem[i]=key[lun][i];      //轮密钥   
Xor(kzmw,keytem,48);   /*S盒置换*/   
 for(i=0;i<8;i++)   {    
	 hang=kzmw[i*6]*2+kzmw[i*6+5];    
	 lie =kzmw[i*6+1]*8+kzmw[i*6+2]*4+kzmw[i*6+3]*2+kzmw[i*6+4]; 
	 tmp[i*4+3]=sbox[i][(hang+1)*16+lie]%2;  
	 tmp[i*4+2]=(sbox[i][(hang+1)*16+lie]/2)%2;    
	 tmp[i*4+1]=(sbox[i][(hang+1)*16+lie]/4)%2;   
     tmp[i*4]=(sbox[i][(hang+1)*16+lie]/8)%2;   }


for(i=0;i<32;i++)  //P置换      
Ri[i]=tmp[Pzh[i]-1];    
Xor(Ri,Li,32);    //异或   
for(i=0;i<32;i++)  //交换左右明文 
  {      Li[i]=ss[i];   }   }  
  for(i=0;i<32;i++)  
  {     tmp[i]=Li[i];   
  Li[i]=Ri[i];    
  Ri[i]=tmp[i];   }   
  for(i=0;i<64;i++)  
PMW[i]=MW[fp[i]-1]; 
  BitToByte(Out,PMW,64);  //位到字节的转换  
} } 

void main() 
{   char Ki[8],jm[8],final[8]; 
 int i0;   
 cout<<"请输入密钥(8字节):"<<endl; 
for(i0=0;i0<8;i0++) 
 cin>>Ki[i0];  keyfc(Ki);  
 cout<<"请输入明文(8字节):"<<endl;  
 for(i0=0;i0<8;i0++) 
	 cin>>jm[i0];  
 DES(final,jm,0);  
 cout<<"加密后:"<<endl;//加密
 for(i0=0;i0<8;i0++) 
	 cout<<final[i0];  
 cout<<endl; 
 cout<<"解密后:"<<endl;   
 DES(jm,final,1); //解密  
 for(i0=0;i0<8;i0++) 
	 cout<<jm[i0];  
 cout<<endl; }

2.1 初始置换
初始置换在第一轮运算之前进行,对输入分组实施如下表所示的变换。初始置换把明文的第58位换到第1位的位置,把第50位换到第2位的位置,把第42位换到第3位的位置,依此类推。
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
初始置换和对应的末置换并不影响DES的安全性,它们的主要目的是为了更容易地将明文和密文数据以字节大小放入DES芯片中。

2.2 密钥置换
在这里插入图片描述
图3 密钥置换过程
由于不考虑每个字节的第8位,DES的密钥由64位减至56位,每个字节第8位作为奇偶校验以确保密钥不发生错误。如下表所示:
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
在DES的每一轮中,从56位密钥产生出不同的48位子密钥(subkey),这些子密钥是这样确定的:
首先,56位密钥被分成两部分,每部分28位。
然后,根据轮数,这两部分分别循环左移1位或2位。每轮移动的位数如下表:
轮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
位数 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1
移动后,就从56位中选出48位。这个运算既置换了每位的顺序,也选择了子密钥,被称为压缩置换(compression permutation)。下表即定义了压缩置换:
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
可以看出,第33位的那一位在输出时移到了第35位,而处于第18位的那一位被忽略了。

2.3 扩展置换
这个运算将数据的右半部分从32位扩展到48位。这个操作两方面的目的:它产生了与密钥同长度的数据以进行异或运算;它提供了更长的结果,使得在替代运算中能进行压缩。
对每个4位输入分组,第1位和第4位分别表示输出分组中的两位,而第2位和第3位分别表示输出分组中的一位,下表给出了哪一输出位对应哪一输入位:
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
处于输入分组中第3位的位置移到了输出分组中的第4位,而输入分组的第21位则移到了输出分组的第30位和第32位。尽管输出分组大于输入分组,但每一个输入分组产生唯一的输出分组。

2.4 S盒代替
在这里插入图片描述

图4 扩展、s盒选择代替
压缩后的密钥与扩展分组异或以后,将48位的结果送入,进行代替运算。替代由8个S盒完成,每一个S盒都由6位输入,4位输出,且这8个S盒是不同的。48 位的输入被分为8个6位的分组,每一个分组对应一个S盒代替操作:分组1由S盒1操作,分组2由S盒2操作,等等。如下图所示:
每一个S盒是一个4行、16列的表。盒中的每一项都是一个4位的数。S盒的6个位输入确定了其对应的输出在哪一行哪一列。下表列出所有8个S盒:
S盒1:
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
S盒2:
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
S盒3:
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
S盒4:
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
S盒5:
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
S盒6:
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
S盒7:
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
S盒8:
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

假定将S盒的6位的输入标记位b1、b2、b3、b4、b5、b6。则b1和b6组合构成了一个2位数,从0到3,它对应着表的一行。从b2到b5构成了一个4位数,从0到15,对应着表中的一列。
例如,假设第6个S盒的输入为110011,第1位和第6位组合形成了11,对应着第6个S盒的第三行,中间4位组合形成了1001,它对应着同一个S盒的第9列,S盒6在第三行第9列的数是14,则用值1110来代替110011。
这是DES算法的关键步骤,所有其他的运算都是线性的,易于分析,而S盒是非线性的,它比DES的其他任何一步提供了更好的安全性。
这个代替过程的结果是8个4位的分组,他们重新合在一起形成了一个32位的分组。

2.5 P盒置换
S盒代替运算的32位输出依照P盒进行置换。该置换把每输入位映射到输出位,任一位不能被映射两次,也不能被略去,下表给出了每位移至的位置:
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
第21位移到了第4位,同时第4位移到了第31位。
最后,将P盒置换的结果与最初的64位分组的左半部分异或,然后左、右半部分交换,接着开始另一轮。

2.6 末置换
末置换是初始置换的逆过程。DES在最后一轮后,左半部分和右半部分并未交换,而是将两部分并在一起形成一个分组作为末置换的输入,该置换如下表如示:
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

3 程序测试

在这里插入图片描述

输入64位明文和64位密钥后得到64位密文,DES这种密码希望采用64位的密钥,然而仅仅采用56位,其余八位可用作奇偶校验或随意设置。通过对比输入的明文及解密结果可知,c程序设计合理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章