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程序設計合理。

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