最近忙,事比较多,活多了,还要降薪,唉。没什么时间看书,将以前的一些技术blog也移到这里。NTLM在去年年底和今年年初研究过一阵子,写了总结和 例子程序。里面涉及很多算法,在网上查了很久。(下面是以前的博客)最近想实现一个通过PROXY穿越的网络编程,将相关的内容进行一下汇总。很多东西来 自网络共产主义,也应该为共产主义有所回馈。介绍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的过程。
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|
|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]为第二步算法的输入。
NTLM的实现:
-
- 实现PROXY穿越(16):NTLM的PROXY穿越
- 实现PROXY穿越(15):NTLM Session Security
- 实现PROXY穿越(14):NTLM type3 Message
- 实现PROXY穿越(13):NTLM type2 Message
- 实现PROXY穿越(12):NTLM type1 Message
- 实现PROXY穿越(11):NTLMv2 session response
- 实现PROXY穿越(10):NTLMv2 response
- 实现PROXY穿越(9):NTLMv1 response
- 实现PROXY穿越(8):NT-Hash的实现
- 实现PROXY穿越(7):MD4和MD5
- 实现PROXY穿越(6):LM-Hash的实现
- 实现PROXY穿越(5):DES算法之三
- 实现PROXY穿越(4):DES算法之二
- 实现PROXY穿越(3):DES算法之一
- 实现PROXY穿越(2):Base64算法
- 实现PROXY穿越(1):流程和NTLM算法