一、實驗目的
1、理解DES算法原理
2、掌握DES的實現
二、實驗環境
Windows XP、VC6.0/Eclipse
三、實驗原理
1、DES算法簡介
DES算法的入口參數有三個:Key、Data、Mode。其中Key為8個字節共64位,是DES算法的工作密鑰;Data也為8個字節64位,是要被加密或被解密的數據;Mode為DES的工作方式,有兩種:加密或解密。
DES算法是這樣工作的:如Mode為加密,則用Key 去把數據Data進行加密, 生成Data的密碼形式(64位)作為DES的輸出結果;如Mode為解密,則用Key去把密碼形式的數據Data解密,還原為Data的明碼形式(64位)作為DES的輸出結果。在通信網絡的兩端,雙方約定一致的Key,在通信的源點用Key對核心數據進行DES加密,然后以密碼形式在公共通信網(如電話網)中傳輸到通信網絡的終點,數據到達目的地后,用同樣的Key對密碼數據進行解密,便再現了明碼形式的核心數據。
2、DES加密算法詳解
DES算法把64位的明文輸入塊變為64位的密文輸出塊,它所使用的密鑰也是64位,其功能是把輸入的64位數據塊經過初始置換按位重新組合,并把輸出分為L0 、R0兩部分,每部分各長32位,然后R0與第一輪子密鑰K1進行f(R0,K1)運算,運算結果再與L0進行按位異或運算,運行結果交換作為下一輪的R1,R0交換作為下一輪的L1,下一輪同樣進行f(Ri,Ki)運算,以此類推共進行16輪,最后一輪不用進行交換,最后進行逆初始置換,即為密文輸出。
3、子密鑰Ki(48bit)的生成算法
初始Key值為64位,但DES算法規定,其中第8、16、......64位是奇偶校驗位,不參與DES運算。故Key 實際可用位數便只有56位。即:經過縮小選擇換位表1的變換后,Key 的位數由64 位變成了56位,此56位分為C0、D0兩部分,各28位,然后分別進行第1次循環左移,得到C1、D1,將C1(28位)、D1(28位)合并得到56位,再經過縮小選擇換位2,從而便得到了密鑰K0(48位)。依此類推,便可得到K1、K2、......、K15,不過需要注意的是,16次循環左移對應的左移位數要依據下述規則進行:
循環左移位數1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
4、DES解密算法
DES算法的解密過程是一樣的,區別僅僅在于第一次迭代時用子密鑰K15,第二次K14、……,最后一次用K0,算法本身并沒有任何變化。
四、實驗步驟及思考題
1、畫出DES算法流程圖
2、編程實現DES
des.cpp
#include<stdio.h>
#include<string.h>
#include"des_encode.h"
int key[16][48];
char str[8];
void main()
{
EncodeMain();
}
void EncodeMain()
{
int i;
char keychar[8];
int key2[8];
int strkey[8];
printf("請輸入8個要加密的字符:\n");
for(i=0;i<8;i++)
scanf("%c",&str[i]);
getchar();
for(i=0;i<8;i++)
strkey[i]=str[i];
printf("\n輸入明文的十六進制為:\n");
for(i=0;i<8;i++)
printf("%10x",strkey[i]);
printf("\n請輸入密鑰(8個字符):\n");
for(i=0;i<8;i++)
scanf("%c",&keychar[i]);
for(i=0;i<8;i++)
key2[i]=keychar[i];
getchar();
// printf("%c",keychar[i]);
Encode(strkey,key2);
printf("\n加密后十六進制密文是:\n");
for(i=0;i<8;i++)
printf("%10x",strkey[i]);
printf("\n\n清輸入解密密碼\n");
for(i=0;i<8;i++)
scanf("%c",&keychar[i]);
for(i=0;i<8;i++)
key2[i]=keychar[i];
Decode(strkey,key2);
for(i=0;i<8;i++)
printf("%10x",strkey[i]);
for(i=0;i<8;i++)
str[i]=strkey[i];
printf("\n明文為:\t");
for(i=0;i<8;i++)
printf("%c",str[i]);
printf("\n\n");
}
void keyBuild(int *keychar){ //創建密鑰數組
int i,j;
int movebit[]={1,1,2,2,2,2,2,2,
1,2,2,2,2,2,2,1};
int midkey2[56];
int midkey[64];
StrtoBin(midkey,keychar);
for(i=0;i<56;i++)
midkey2[i]=midkey[PC1[i]-1];
for(i=0;i<16;i++)
keyCreate(midkey2,movebit[i],i);
}
void StrtoBin(int *midkey,int *keychar){ //轉換成二進制
int trans[8],i,j,k,n;
n=0;
for(i=0;i<8;i++){
j=0;
while(keychar[i]!=0){
trans[j]=keychar[i]%2;
keychar[i]=keychar[i]/2;
j++;
}
for(k=j;k<8;k++)trans[k]=0;
for(k=0;k<8;k++)
midkey[n++]=trans[7-k];
}
}
void keyCreate(int *midkey2,int movebit,int n){
int i,temp[4];
temp[0]=midkey2[0];
temp[1]=midkey2[1];
temp[2]=midkey2[28];
temp[3]=midkey2[29];
if(movebit==2){
for(i=0;i<26;i++){
midkey2[i]=midkey2[i+2];
midkey2[i+28]=midkey2[i+30];
}
midkey2[26]=temp[0];midkey2[27]=temp[1];
midkey2[54]=temp[2];midkey2[55]=temp[3]; }
else
{ for(i=0;i<27;i++){
midkey2[i]=midkey2[i+1];
midkey2[i+28]=midkey2[i+29];
}
midkey2[27]=temp[0];midkey2[55]=temp[2];
}
for(i=0;i<48;i++)
key[n][i]=midkey2[PC2[i]-1];
}
void EncodeData(int *lData,int *rData,int *str){ //加密函數
int i,j,temp[8],lint,rint;//int h;
int data[64];
lint=0,rint=0;
for(i=0;i<4;i++){
j=0;
while(str[i]!=0){
temp[j]=str[i]%2;
str[i]=str[i]/2;
j++;
}
while(j<8)temp[j++]=0;
for(j=0;j<8;j++)
lData[lint++]=temp[7-j];
j=0;
while(str[i+4]!=0){
temp[j]=str[i+4]%2;
str[i+4]=str[i+4]/2;
j++;
}
while(j<8)temp[j++]=0;
for(j=0;j<8;j++)rData[rint++]=temp[7-j];
}
for(i=0;i<32;i++){
data[i]=lData[i];
data[i+32]=rData[i];
}
for(i=0;i<32;i++){
lData[i]=data[IP1[i]-1];//printf("P1:%5d:%5d,%5d\n",IP1[i],lData[i],data[IP1[i]-1]);
rData[i]=data[IP1[i+32]-1];
}
}
void F(int *rData,int *key){ //F function
int i,rDataP[48];
Expand(rData,rDataP);
for(i=0;i<48;i++){
rDataP[i]=rDataP[i]^key[i];// printf("%10d",rDataP[i]);if((i+1)%6==0)printf("\n");
}
ExchangeS(rDataP,rData);
ExchangeP(rData);
}
void Expand(int *rData,int *rDataP){ //擴展函數
int i;
for(i=0;i<48;i++)
rDataP[i]=rData[Ex[i]-1];
}
void ExchangeS(int *rDataP,int *rData){ //S圖變化
int i,n,linex,liney;
linex=liney=0;
for(i=0;i<48;i+=6){
n=i/6; //printf("%10d\n",(rDataP[i]<<1));
linex=(rDataP[i]<<1)+rDataP[i+5];
liney=(rDataP[i+1]<<3)+(rDataP[i+2]<<2)+(rDataP[i+3]<<1)+rDataP[i+4];
FillBin(rData,n,s[n][linex][liney]);
}
}
void ExchangeP(int *rData){ //P變化
int i,temp[32];
for(i=0;i<32;i++)
temp[i]=rData[i];
for(i=0;i<32;i++)
rData[i]=temp[P[i]-1];
}
void FillBin(int *rData,int n,int s){ // 數據以二進制的s-圖改變函數的調用;
int temp[4],i;
for(i=0;i<4;i++){
temp[i]=s%2;
s=s/2;
}
for(i=0;i<4;i++)
rData[n*4+i]=temp[3-i];
}
void DecodeData(int *str,int *lData,int *rData){ //從二進制解析數據
int i;int a,b;int data[64];
a=0,b=0;
for(i=0;i<32;i++){
data[i]=lData[i];
data[i+32]=rData[i];
}
for(i=0;i<32;i++){
lData[i]=data[IP2[i]-1];
rData[i]=data[IP2[i+32]-1];
}
for(i=0;i<32;i++){
a=(lData[i]&0x1)+(a<<1);
b=(rData[i]&0x1)+(b<<1);
if((i+1)%8==0){
str[i/8]=a;a=0;//printf("%d",i/8);
str[i/8+4]=b;b=0;//printf("%d",i/8+4);
}
}
}
void Encode(int *str,int *keychar){ //加密:輸入8字節加密字符,8字節密鑰
int lData[32],rData[32],temp[32],rDataP[48];
int i,j;
keyBuild(keychar);
EncodeData(lData,rData,str);
for(i=0;i<16;i++){
for(j=0;j<32;j++)
temp[j]=rData[j];
F(rData,key[i]);
for(j=0;j<32;j++){
rData[j]=rData[j]^lData[j];
}
for(j=0;j<32;j++)
lData[j]=temp[j];
}
DecodeData(str,rData,lData);
}
void Decode(int *str,int *keychar){ //解密:輸出8字節加密字符,8字節密鑰
int lData[32],rData[32],temp[32],rDataP[48];
int i,j;
keyBuild(keychar);
EncodeData(lData,rData,str); //這個位置
for(i=0;i<16;i++){
for(j=0;j<32;j++)
temp[j]=rData[j];
F(rData,key[15-i]);
for(j=0;j<32;j++){
rData[j]=rData[j]^lData[j];
}
for(j=0;j<32;j++){
lData[j]=temp[j];
}
}
DecodeData(str,rData,lData);
}
des_encode.h
void EncodeMain();
void Decode(int *str,int *keychar); ////加密:輸入8字節加密字符,8字節密鑰
void Encode(int *str,int *keychar); ////解密:輸出8字節加密字符,8字節密鑰
void keyBuild(int *keychar); //創建密鑰數組
void StrtoBin(int *midkey,int *keychar); //轉換成二進制
void keyCreate(int *midkey2,int movebit,int i); //調用密鑰創建
void EncodeData(int *lData,int *rData,int *srt); //解密函數
void F(int *rData,int *key); //F function
void Expand(int *rData,int *rDataP);
void ExchangeS(int *rDataP,int *rData);
void ExchangeP(int *rData);
void FillBin(int *rData,int n,int s); // 數據以二進制的s-圖改變函數的調用;
void DecodeData(int *str,int *lData,int *rData); //從二進制解析數據
int IP1[]={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,
};
int IP2[]={40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, //OPP的初始變化
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
};
int s[][4][16]={{ //S-圖形變化
{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}
},
{
{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}
},
{
{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}
},
{
{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}
},
{
{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}
},
{
{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}
},
{
{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}
},
{
{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 Ex[48]={ 32,1,2,3,4,5, //Expand array
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 P[32]={16,7,20,21, //P-change
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 PC1[56]={57,49,41,33,25,17,9, //PC-1 in keyBuild
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,33,15,
7,62,54,46,38,30,22,
14,6,61,53,45,37,29,
21,13,5,28,20,12,4
};
int PC2[48]={14,17,11,24,1,5, //PC-2 in keyBuild
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
};
3、驗證效果,截圖
![{BN80F0PR]RIQ4)3@XEQO_G.png](http://upload-images.jianshu.io/upload_images/3125377-fb71ed826c730367.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
【思考題】
1、請說說DES算法中子密鑰是怎么得到的。
- 移位和循環移位:
移位就是將一段數碼按照規定的位數整體性地左移或右移。循環右移就是當右移時,把數碼的最后的位移到數碼的最前頭,循環左移正相反。例如,對十進制數碼12345678循環右移1位(十進制位)的結果為81234567,而循環左移1位的結果則為23456781。
當時自己在這里栽過很大的跟頭,這里的循環移位,指的是前后28位密碼的位置循環左移,比如
49 42 35 28 21 14 7 42 35 28 21 14 7 0
0 50 43 36 29 22 15 循環左移一位 50 43 36 29 22 15 8
8 1 51 44 37 30 23 ————————> 1 51 44 37 30 23 16
16 9 2 52 45 38 31 9 2 52 45 38 31 49 - 置換:
就是將數碼中的某一位的值根據置換表的規定,用另一位代替。它不像移位操作那樣整齊有序,看上去雜亂無章。這正是加密所需,被經常應用。
DES密鑰擴展算法:
for each round i = 1,2,3....n
LK = cyclically left shift LK by ri bits
RK = cyclically left shift RK by ri bits
The left half of subkey Ki consists of bits of LP of LK
The right half of subkey Ki consits of bits of RP of RK
next i
具體的操作:
特別注意:這里講的數字都是指密鑰的具體位置,而不是密鑰的內容
1. 我們將DES的56位密鑰從左到右從0開始編號。首先擴展DES密鑰的前28位,并進行置換,結果稱為LK,DES密鑰的LK是原始密鑰的下列各位:
49 42 35 28 21 14 7
0 50 43 36 29 22 15
8 1 51 44 37 30 23
16 9 2 52 45 38 31
通俗講,就是說第一位前面的28位密鑰中,第一位放的元素就是原先56中的第49位,第二位就是原先的42位
2. 類似的,DES密鑰的剩余28位稱為RK,由原始密鑰的下列各位構成
55 48 41 34 27 20 13
6 54 47 40 33 26 19
12 5 53 46 39 32 25
18 11 4 24 17 10 3
3. 在進行密鑰擴張算法之前,還需要定義LP置換:
13 16 10 23 0 4 2 27 14 5 20 9
22 18 11 3 25 7 15 6 26 19 12 1
這就是將經過移位之后的左邊的28位密鑰重現編號,再按下標放好
缺少8,17,21,24
4.RP置換
12 23 2 8 18 26 1 11 22 16 4 19
15 20 10 27 5 24 17 13 21 7 0 3
缺少了6,9,14,25
2、請說說16次迭代中的f函數的原理。
函數 f:{0 , 1}32 ? {0 , 1}48?{0 , 1}32 的輸入是一個32比特串(當前狀態的右半部)和子密鑰。密鑰編排方案),...,,(3221kkk由16個48比特的子密鑰組成,這些子密鑰由56比特的種子密鑰k導出。每個ki都是由k置換選擇而來(子密鑰的產生過程將在后面詳細說明)。
密碼函數f是整個加密的關鍵部分,它包含了如下四種功能:
i 擴展函數E
ii 模2加法
iii S盒運算
iv.置換函數P
五、實驗小結
(實驗過程中遇到什么問題?如何解決?)
代碼不會寫,百度!!!