DES加密算法 設計與實現

一、實驗目的

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算法流程圖
1.png
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算法中子密鑰是怎么得到的。
  1. 移位和循環移位:
      移位就是將一段數碼按照規定的位數整體性地左移或右移。循環右移就是當右移時,把數碼的最后的位移到數碼的最前頭,循環左移正相反。例如,對十進制數碼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
  2. 置換:
      就是將數碼中的某一位的值根據置換表的規定,用另一位代替。它不像移位操作那樣整齊有序,看上去雜亂無章。這正是加密所需,被經常應用。
      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

五、實驗小結

(實驗過程中遇到什么問題?如何解決?)
代碼不會寫,百度!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容