0
点赞
收藏
分享

微信扫一扫

实现PROXY穿越(3):DES算法之一


  

 

   在NTLM中使用DES算法生成LM-HASH和NTLM-HASH(以后在介绍)。我们现讨论DES算法的实现。 DES是Data Encryption Standard(数据加密标准)的缩写。它是由IBM公司研制的一种加密算法,美国国家标准局于1977年公布把它作为非机要部门使用的数据加密标准,二十年来,它一直活跃在国际保密通信的舞台上,扮演了十分重要的角色。而DES算法本身称自己为DEA(Data Encryption Althorithm),因此DES和DEA实际是同一个东东。
  DES输入64bit的数据源,通过56bits的key(由8bytes去掉CRC校验位获得,输入也可以看作是64bits,至少在程序代码中是这样体现),生成一个64bits的结果,DES属于对称加密方式。一共分为三个步骤。
  在实现的过程中,最为郁闷的是网上有很多代码和例子,也有一些检测工具,例如Crytotool1.2,但是很奇怪,他们给出的结果不一样,因此有必要认真了解一下整个DES的过程。

步骤一:源和key的初始化序列改动(Initail permutation)


通过对比特的序列移动,生成新的源'和key’,用于后续的算法计算。

A:对源的处理
  8字节,共64bits,从1到64按下面左阵列的摆列方式,经过序列移动,成规下面右阵列的排列方式,实际上新的第一个8bit就是左阵列的第2 列,从下到上的顺序,后面的7组8比特分别为第4、6、8、1、3、5、7列从下到上的排序。这种方式,我想对于芯片实现是很便利的,可惜C编程语言不等 直接按列处理,只好写段代码来实现。
| 1  2  3  4  5  6  7  8|    |58 50 42 34 26 18 10 2|
| 9 10 11 12 13 14 15 16|    |60 52 44 36 28 20 12 4|
|17 18 19 20 21 22 23 24|    |62 54 46 38 30 22 14 6|
|25 26 27 28 29 30 31 32|    |64 56 48 40 32 24 16 8|
|33 34 35 36 37 38 39 40| -> |57 49 41 33 25 17  9 1|
|41 42 43 44 45 46 47 48|    |59 51 43 35 27 19 11 3|
|49 50 51 52 53 54 55 56|    |61 53 45 37 29 21 13 5|
|57 58 59 60 61 62 63 64|    |63 55 47 39 31 23 15 7|


 实现代码:

//变换序列 
 static int ip_data_seq[] = {
     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};

//由于后面存在大量的比特操作,而C程序中一般以字节为单位,因此我们将字节中的比特分别 
//存贮在8个字节中,以方便后面的大量运算 
 static void storebit(IN unsigned char * data, IN int data_len, OUT unsigned char * dst){
     int i = 0;
     for(i = 0 ; i < data_len;i ++){
         dst[i*8] = getbit(data[i],7);
         dst[i*8 + 1] = getbit(data[i],6);
         dst[i*8 + 2] = getbit(data[i],5);
         dst[i*8 + 3] = getbit(data[i],4);
         dst[i*8 + 4] = getbit(data[i],3);
         dst[i*8 + 5] = getbit(data[i],2);
         dst[i*8 + 6] = getbit(data[i],1);
         dst[i*8 + 7] = getbit(data[i],0);
     }
 }
//这是storebit得反操作。 
 static void parsebit(IN unsigned char * data,OUT unsigned char * dst,IN int dst_len){
     int i = 0;
     for(i = 0 ; i < dst_len ; i ++){
         dst[i] = data[8*i] * 0x80 +
             data[8*i + 1] * 0x40 +
             data[8*i + 2] * 0x20 +
             data[8*i + 3] * 0x10 +
             data[8*i + 4] * 0x8 +
             data[8*i + 5] * 0x4 +
             data[8*i + 6] * 0x2 +
             data[8*i + 7];
     }
 }

//移位操作函数 
 static void initail_permutation(IN unsigned char * data,IN int * schedule, IN int num,
                                 OUT unsigned char * dst){
     int i = 0;
     unsigned char * temp;
     temp = (unsigned char *)malloc(num);

     for(i = 0 ; i < num; i ++){
         temp[i] = data[schedule[i] - 1];
     }
     memcpy(dst,temp,num);
     free(temp);
 }

//算法主函数 
 void algorithm_des(IN unsigned char * src, IN unsigned char * secrect,
                    OUT unsigned char * dst){
     unsigned char s[64],key[64],L[32],R[32],K[48],E[48];
     int i = 0;

     //步骤1
    storebit(src,8,s); 
    initail_permutation(s,ip_data_seq,64,s); 
 }



B:对key的处理


  对于输入的8字节的key,每个字节去除其CRC校验位(第8位),然后经过类似的序列移位生成了56bit的新的key。从这个处理,我们也可以看出DES算法的古老,采用流的概念,而CRC校验位用于初期比较古老的误码率高的通信中。


  这种以通信以流的方式传递,需要注意和我们程序中的顺序问题。如果我们使用byte(unsinged char)来放置一8bit的信息,那么第一位是我们byte的高位。这与我们网络编程中碰到的little_endian和big_endian的情况有点类似。闲话少谈,移动位的方式如下:


| 1 2  3  4  5  6  7  8 |    |57 49 41 33 25 17  9|    |57 49 41 33 25 17  9  1|


| 9 10 11 12 13 14 15 16|    | 1 58 50 42 34 26 18|    |58 50 42 34 26 18 10  2|
|17 18 19 20 21 22 23 24|    |10  2 59 51 43 35 27|    |59 51 43 35 27 19 11  3|
|25 26 27 28 29 30 31 32|    |19 11  3 60 52 44 36|    |60 52 44 36            |
|33 34 35 36 37 38 39 40| -> |63 55 47 39 31 23 15| -> |63 55 47 39 31 23 15  7|
|41 42 43 44 45 46 47 48|    | 7 62 54 46 38 30 22|    |62 54 46 38 30 22 14  6|
|49 50 51 52 53 54 55 56|    |14  6 61 53 45 37 29|    |61 53 45 37 29 21 13  5|
|57 58 58 60 61 62 63 64|    |21 13  5 28 20 12  4|    |28 20 12  4            |
  中间和右图是一样的,只是我们采用7bit一组还是按照8bit一组的方式存放,我们希望通过右图给出一个有规律的处理。

static int ip_key_seq[] ={
     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};

//算法主函数 
 void algorithm_des(IN unsigned char * src, IN unsigned char * secrect,
                    OUT unsigned char * dst){
     unsigned char s[64],key[64],L[32],R[32],K[48],E[48];
     int i = 0;

     //步骤1
    storebit(src,8,s); 
    storebit(secrect,8,key); 
    initail_permutation(s,ip_data_seq,64,s); 
    initail_permutation(key,ip_key_seq,56,key); 
 }



OK,终于完成了第一步,得到了s[64]和key[56]为第二步算法的输入。






举报

相关推荐

0 条评论