NTLM Protocol - 3. MD4 编码

来源:互联网 发布:淘宝买药怎么取消订单 编辑:程序博客网 时间:2024/05/18 00:18

更确切的来说此章应为介绍如何使用 MD4 编码, 而此章所表达的重点更应该为 NTLM 中 DES 与 MD4 所扮演的角色. 使用 MD4 编码来加密资料, 在 Perl 的世界中, 有许多开发者创造了许多模组供我们使用, 而 Digest::MD4 就是其中一个, 它是由Mike McCauley所开发, 使用它可以将 MD4 加密变的很简单, 只要使用它所提供的方法, 以下就是一个例子:


上例实现了 $a 字串用 MD4 加密所得出的 16 进位字串.

有了 DES 及 MD4 的基础后, 可以回到 《NTLM Protocol - 1.NTLM 的通讯过程》中所提到的 LMRESP 及 NTRESP 这两个长度为 24 Bytes 加密后的资料, 首先先介绍 LMRESP 是如何根据 PASSWORD 与 NONCE 计算出来的.

举例来说, 假设 PASSWORD = '1qaz2wsx3WSX', 将其全部转成大写可得 '1QAZ2WSX3WSX', 再转成 16 进位字串可得 UK, 以 Byte 来表示如下:

UK[0] = 31, UK[1] = 51, UK[2] = 41, UK[3] = 5a, UK[4] = 32, UK[5] = 57
UK[6] = 53, UK[7] = 58
UK[8] = 33, UK[9] = 57, UK[10] = 53, UK[11] = 58

以 8 Byte 为一组当作一个 Base Key, 第二个 Base Key 会重复第一个 Base Key 的最后一个值, 再依序排出, 后面不够的补 \x00, 所以可以得到 BK1 与 BK2 如下:

BK1[0] = 31         BK2[0] = 58  

BK1[1] = 51         BK2[1] = 33

BK1[2] = 41         BK2[2] = 57

BK1[3] = 5a         BK2[3] = 53

BK1[4] = 32         BK2[4] = 58

BK1[5] = 57         BK2[5] = 00

BK1[6] = 53         BK2[6] = 00

BK1[7] = 58         BK2[7] = 00

将两组基钥经过如下转换公式, 我们称为 Z 函数, 可得出 CK1 与 CK2, 转换公式为:

key[0] = key_56[0];
key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
key[7] =  (key_56[6] << 1) & 0xFF;

key_56 表示所传入的 BK1 或 BK2 的前 7 位元素, 于是由上式可得转变后的 CK1 与 CK2 分别为:

CK1[0] = 31         CK2[0] = 58

CK1[1] = a8         CK2[1] = 19

CK1[2] = 50         CK2[2] = d5

CK1[3] = 2b         CK2[3] = ea

CK1[4] = a3         CK2[4] = 35

CK1[5] = 92         CK2[5] = c0

CK1[6] = 5d         CK2[6] = 00

CK1[7] = a6         CK2[7] = 00

将 CK1 与 CK2 中的每一个元素, 都经过 set_odd_parity 的运算后, 可得到 DK1 与 DK2, 而 set_odd_parity 则可以如下算法表达:

#!/usr/bin/perl@odd_parity=(  1,  1,  2,  2,  4,  4,  7,  7,  8,  8, 11, 11, 13, 13, 14, 14, 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254);for $i (@ARGV) {  if($i =~ /^0x/) {    # convert hex to binary    $i = pack("H*", substr($i,2));  }  @bytes=unpack("C*", $i);  print join(',', @bytes)."\n";    print "0x";  foreach $byte (@bytes) {    $byte = $odd_parity[$byte];    print sprintf("%02x", $byte);  }  print "\n";  #print "\"";  foreach $byte (@bytes) {    $byte = $odd_parity[$byte];    #print pack("c", $byte);  }  #print "\"\n";}

举例来说,若想计算 CK1 经运算后的值可执行如下:


CK1[0] => 31, CK1[1] => a8, CK1[2] => 51, CK1[3] => 2a, 所以由此可得 DK1 与 DK2 为:

DK1[0] = 31         DK2[0] = 58

DK1[1] = a8         DK2[1] = 19

DK1[2] = 51         DK2[2] = d5

DK1[3] = 2a         DK2[3] = ea

Dk1[4] = a2         DK2[4] = 34

DK1[5] = 92         DK2[5] = c1

DK1[6] = 5d         DK2[6] = 01

DK1[7] = a7         DK2[7] = 01

分别以 DK1 与 DK2 为 KEY, 对 MAGIC = '4b47532140232425' 进行 DES 编码则分别可得 EK1 与 EK2, EK1 = '77110412e3544d2f', EK2 = '083b7034aafcdbff', 将 EK1 与 EK2 组合起来后, 后 5 位以 \x00 递补, 则成 21 Bytes 的 FK, FK = '\x77110412e3544d2f083b7034aafcdbff0000000000', 将 FK 分成三段, 每段 8 个数, 下一段重复上一段的最后一个再往后算上 7 个, 于是可以得到 GK1, GK2, GK3:

GK1[0] = 77     GK2[0] = 2f     GK3[0] = db 

GK1[1] = 11     GK2[1] = 08     GK3[1] = ff

GK1[2] = 04     GK2[2] = 3b     GK3[2] = 00

GK1[3] = 12     GK2[3] = 70     GK3[3] = 00

GK1[4] = e3     GK2[4] = 34     GK3[4] = 00

GK1[5] = 54     GK2[5] = aa     GK3[5] = 00

GK1[6] = 4d     GK2[6] = fc     GK3[6] = 00

GK1[7] = 2f     GK2[7] = db     GK3[7] = 00

GK1, GK2, GK3 经过前面所提到的 Z 函数转换后可得到 HK1, HK2, HK3:

HK1[0] = 77     HK2[0] = 2f     HK3[0] = db

HK1[1] = 88     HK2[1] = 84     HK3[1] = ff

HK1[2] = 41     HK2[2] = 0e     HK3[2] = c0

HK1[3] = 82     HK2[3] = 6e     HK3[3] = 00

HK1[4] = 2e     HK2[4] = 03     HK3[4] = 00

HK1[5] = 1a     HK2[5] = a5     HK3[5] = 00

HK1[6] = 51     HK2[6] = ab     HK3[6] = 00

HK1[7] = 9a     HK2[7] = f8     HK3[7] = 00

HK1, HK2, HK3 再经过 set_odd_parity 运算即可得到 IK1, IK2, IK3

IK1[0] = 76     IK2[0] = 2f     IK3[0] = da

IK1[1] = 89     IK2[1] = 85     IK3[1] = fe

IK1[2] = 40     IK2[2] = 0e     IK3[2] = c1

IK1[3] = 83     IK2[3] = 6e     IK3[3] = 01

IK1[4] = 2f     IK2[4] = 02     IK3[4] = 01

IK1[5] = 1a     IK2[5] = a4     IK3[5] = 01

IK1[6] = 51     IK2[6] = ab     IK3[6] = 01

IK1[7] = 9b     IK2[7] = f8     IK3[7] = 01

分别以 IK1, IK2, IK3 为 KEY 对 NONCE = '6b4ba459beedb768' 进行 DES 加密则可得到 EN1, EN2, EN3:

EN1 = '6aeb443da7d6243c'

EN2 = '781b33ca6efaff4a'

EN3 = '208d2e7dea6f481a'

EN1 就是 LMRESP[0..7], EN2 就是 LMRESP[8..15], EN3 就是 LMRESP[16..23], 这样就可以得到 LMRESP[24]:


计算出 LMRESP 后再来看看 NTRESP 是怎么计算出来的?

将 PASSWORD = '1qaz2wsx3WSX' 展成 16 进位字串 '3171617a3277737833575358', 在每一位后递补一个 \x00, 于是新形成的 PW = '3100710061007a0032007700730078003300570053005800', PW 经过 MD4 加密后可得 PWMD4 = '3e1d8884fa3bffb0f8cadd475428e47f', 这在介绍本章稍早前算过, 不再赘述, 与计算 LMRESP 类似, 将 PWMD4 后面补上 5 个 \x00, 成为长度 21 的一个基钥, 将其分为三段, 每段 8 Bytes, 则可得 MK1, MK2, Mk3:

MK1[0] = 3e     MK2[0] = b0     MK3[0] = e4

MK1[1] = 1d     MK2[1] = f8     MK3[1] = 7f

MK1[2] = 88     MK2[2] = ca     MK3[2] = 00

MK1[3] = 84     MK2[3] = dd     MK3[3] = 00

MK1[4] = fa     MK2[4] = 47     MK3[4] = 00

MK1[5] = 3b     MK2[5] = 54     MK3[5] = 00

MK1[6] = ff     MK2[6] = 28     MK3[6] = 00

MK1[7] = b0     MK2[7] = e4     MK3[7] = 00

再经过 Z 函数以及 set_odd_parity 之后, 可得 NK1, NK2, NK3, 分别以这三组 KEY 对 NONCE 'ad77b52ebce8f59b' 进行 DES 加密后, 组合起来即可得到 NTRESP[24]:


至此 DES 编码及 MD4 编码已介绍完毕, 下一章节将再回顾 NTLM 的完整的通讯流程.