一、實驗目的
1、理解DES算法原理
2、掌握DES的實現(xiàn)
二、實驗環(huán)境
Windows XP、VC6.0/Eclipse
三、實驗原理
1、DES算法簡介
DES算法的入口參數(shù)有三個:Key、Data、Mode。其中Key為8個字節(jié)共64位,是DES算法的工作密鑰;Data也為8個字節(jié)64位,是要被加密或被解密的數(shù)據(jù);Mode為DES的工作方式,有兩種:加密或解密。
DES算法是這樣工作的:如Mode為加密,則用Key 去把數(shù)據(jù)Data進行加密, 生成Data的密碼形式(64位)作為DES的輸出結果;如Mode為解密,則用Key去把密碼形式的數(shù)據(jù)Data解密,還原為Data的明碼形式(64位)作為DES的輸出結果。在通信網絡的兩端,雙方約定一致的Key,在通信的源點用Key對核心數(shù)據(jù)進行DES加密,然后以密碼形式在公共通信網(如電話網)中傳輸?shù)酵ㄐ啪W絡的終點,數(shù)據(jù)到達目的地后,用同樣的Key對密碼數(shù)據(jù)進行解密,便再現(xiàn)了明碼形式的核心數(shù)據(jù)。
2、DES加密算法詳解
DES算法把64位的明文輸入塊變?yōu)?4位的密文輸出塊,它所使用的密鑰也是64位,其功能是把輸入的64位數(shù)據(jù)塊經過初始置換按位重新組合,并把輸出分為L0 、R0兩部分,每部分各長32位,然后R0與第一輪子密鑰K1進行f(R0,K1)運算,運算結果再與L0進行按位異或運算,運行結果交換作為下一輪的R1,R0交換作為下一輪的L1,下一輪同樣進行f(Ri,Ki)運算,以此類推共進行16輪,最后一輪不用進行交換,最后進行逆初始置換,即為密文輸出。
3、子密鑰Ki(48bit)的生成算法
初始Key值為64位,但DES算法規(guī)定,其中第8、16、......64位是奇偶校驗位,不參與DES運算。故Key 實際可用位數(shù)便只有56位。即:經過縮小選擇換位表1的變換后,Key 的位數(shù)由64 位變成了56位,此56位分為C0、D0兩部分,各28位,然后分別進行第1次循環(huán)左移,得到C1、D1,將C1(28位)、D1(28位)合并得到56位,再經過縮小選擇換位2,從而便得到了密鑰K0(48位)。依此類推,便可得到K1、K2、......、K15,不過需要注意的是,16次循環(huán)左移對應的左移位數(shù)要依據(jù)下述規(guī)則進行:
循環(huán)左移位數(shù)1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
4、DES解密算法
DES算法的解密過程是一樣的,區(qū)別僅僅在于第一次迭代時用子密鑰K15,第二次K14、……,最后一次用K0,算法本身并沒有任何變化。
四、實驗步驟及思考題
1、畫出DES算法流程圖
2、編程實現(xiàn)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){ //創(chuàng)建密鑰數(shù)組
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){ //加密函數(shù)
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){ //擴展函數(shù)
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){ // 數(shù)據(jù)以二進制的s-圖改變函數(shù)的調用;
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){ //從二進制解析數(shù)據(jù)
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字節(jié)加密字符,8字節(jié)密鑰
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字節(jié)加密字符,8字節(jié)密鑰
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字節(jié)加密字符,8字節(jié)密鑰
void Encode(int *str,int *keychar); ////解密:輸出8字節(jié)加密字符,8字節(jié)密鑰
void keyBuild(int *keychar); //創(chuàng)建密鑰數(shù)組
void StrtoBin(int *midkey,int *keychar); //轉換成二進制
void keyCreate(int *midkey2,int movebit,int i); //調用密鑰創(chuàng)建
void EncodeData(int *lData,int *rData,int *srt); //解密函數(shù)
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); // 數(shù)據(jù)以二進制的s-圖改變函數(shù)的調用;
void DecodeData(int *str,int *lData,int *rData); //從二進制解析數(shù)據(jù)
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算法中子密鑰是怎么得到的。
- 移位和循環(huán)移位:
移位就是將一段數(shù)碼按照規(guī)定的位數(shù)整體性地左移或右移。循環(huán)右移就是當右移時,把數(shù)碼的最后的位移到數(shù)碼的最前頭,循環(huán)左移正相反。例如,對十進制數(shù)碼12345678循環(huán)右移1位(十進制位)的結果為81234567,而循環(huán)左移1位的結果則為23456781。
當時自己在這里栽過很大的跟頭,這里的循環(huán)移位,指的是前后28位密碼的位置循環(huán)左移,比如
49 42 35 28 21 14 7 42 35 28 21 14 7 0
0 50 43 36 29 22 15 循環(huán)左移一位 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 - 置換:
就是將數(shù)碼中的某一位的值根據(jù)置換表的規(guī)定,用另一位代替。它不像移位操作那樣整齊有序,看上去雜亂無章。這正是加密所需,被經常應用。
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
具體的操作:
特別注意:這里講的數(shù)字都是指密鑰的具體位置,而不是密鑰的內容
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位密鑰重現(xiàn)編號,再按下標放好
缺少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函數(shù)的原理。
函數(shù) f:{0 , 1}32 ? {0 , 1}48?{0 , 1}32 的輸入是一個32比特串(當前狀態(tài)的右半部)和子密鑰。密鑰編排方案),...,,(3221kkk由16個48比特的子密鑰組成,這些子密鑰由56比特的種子密鑰k導出。每個ki都是由k置換選擇而來(子密鑰的產生過程將在后面詳細說明)。
密碼函數(shù)f是整個加密的關鍵部分,它包含了如下四種功能:
i 擴展函數(shù)E
ii 模2加法
iii S盒運算
iv.置換函數(shù)P
五、實驗小結
(實驗過程中遇到什么問題?如何解決?)
代碼不會寫,百度!!!