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阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容