OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/http/ntlm_client.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/md5.h" | |
11 #include "net/http/des.h" | |
12 #include "net/http/md4.h" | |
13 #include "net/http/ntlm_buffer_writer.h" | |
14 | |
15 namespace net { | |
16 | |
17 namespace ntlm { | |
18 | |
19 void GenerateNtlmHashV1(const base::string16& password, uint8_t* hash) { | |
20 size_t length = password.length() * 2; | |
21 // hash param must have at least 16 bytes of space. | |
22 NtlmBufferWriter writer(length); | |
23 | |
24 // The writer will handle the big endian case if necessary. | |
25 bool result = writer.WriteUtf16String(password); | |
26 DCHECK(result); | |
27 | |
28 std::unique_ptr<uint8_t[]> buffer = writer.ReleaseBuffer(); | |
29 | |
30 weak_crypto::MD4Sum(buffer.get(), length, hash); | |
31 } | |
32 | |
33 void GenerateResponseDesl(const uint8_t* hash, | |
34 const uint8_t* challenge, | |
35 uint8_t* response) { | |
36 // hash param must be 16 bytes. | |
37 // challenge param must be 8 bytes. | |
38 // response param must be at least 24 bytes. | |
39 | |
40 // See DESL(K, D) function in Section 6 Appendix A of NTLMSSP specification. | |
41 uint8_t key1[8]; | |
42 uint8_t key2[8]; | |
43 uint8_t key3[8]; | |
44 | |
45 // The last 2 bytes of the hash are zero padded (5 zeros) as the | |
46 // input to generate key3. | |
47 uint8_t padded_hash[7]; | |
48 padded_hash[0] = hash[14]; | |
49 padded_hash[1] = hash[15]; | |
50 memset(padded_hash + 2, 0, 5); | |
51 | |
52 DESMakeKey(hash, key1); | |
53 DESMakeKey(hash + 7, key2); | |
54 DESMakeKey(padded_hash, key3); | |
55 | |
56 DESEncrypt(key1, challenge, response); | |
57 DESEncrypt(key2, challenge, response + 8); | |
58 DESEncrypt(key3, challenge, response + 16); | |
59 } | |
60 | |
61 void GenerateNtlmResponseV1(const base::string16& password, | |
62 const uint8_t* challenge, | |
63 uint8_t* ntlm_response) { | |
64 uint8_t ntlm_hash[NTLM_HASH_LEN]; | |
65 GenerateNtlmHashV1(password, ntlm_hash); | |
66 GenerateResponseDesl(ntlm_hash, challenge, ntlm_response); | |
67 } | |
68 | |
69 void GenerateResponsesV1(const base::string16& password, | |
70 const uint8_t* server_challenge, | |
71 uint8_t* lm_response, | |
72 uint8_t* ntlm_response) { | |
73 GenerateNtlmResponseV1(password, server_challenge, ntlm_response); | |
74 | |
75 // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the | |
76 // same. So just copy the ntlm_response into the lm_response. | |
77 memcpy(lm_response, ntlm_response, RESPONSE_V1_LEN); | |
78 } | |
79 | |
80 void GenerateLMResponseV1WithSS(const uint8_t* client_challenge, | |
81 uint8_t* lm_response) { | |
82 // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of | |
83 // client challenge and 16 bytes of zeros. (See 3.3.1) | |
84 memcpy(lm_response, client_challenge, CHALLENGE_LEN); | |
85 memset(lm_response + CHALLENGE_LEN, 0, RESPONSE_V1_LEN - CHALLENGE_LEN); | |
86 } | |
87 | |
88 void GenerateSessionHashV1WithSS(const uint8_t* server_challenge, | |
89 const uint8_t* client_challenge, | |
90 base::MD5Digest* session_hash) { | |
91 base::MD5Context ctx; | |
92 base::MD5Init(&ctx); | |
93 base::MD5Update( | |
94 &ctx, base::StringPiece(reinterpret_cast<const char*>(server_challenge), | |
95 CHALLENGE_LEN)); | |
96 base::MD5Update( | |
97 &ctx, base::StringPiece(reinterpret_cast<const char*>(client_challenge), | |
98 CHALLENGE_LEN)); | |
99 | |
100 base::MD5Final(session_hash, &ctx); | |
101 } | |
102 | |
103 void GenerateNtlmResponseV1WithSS(const base::string16& password, | |
104 const uint8_t* server_challenge, | |
105 const uint8_t* client_challenge, | |
106 uint8_t* ntlm_response) { | |
107 // Generate the NTLMv1 Hash. | |
108 uint8_t ntlm_hash[NTLM_HASH_LEN]; | |
109 GenerateNtlmHashV1(password, ntlm_hash); | |
asanka
2017/06/23 21:29:11
Minor nit: It's easier to follow along with the sp
| |
110 | |
111 // Generate the NTLMv1 Session Hash. | |
112 base::MD5Digest session_hash; | |
113 GenerateSessionHashV1WithSS(server_challenge, client_challenge, | |
114 &session_hash); | |
115 | |
116 // Only the first 8 bytes of |session_hash.a| are actually used. | |
117 GenerateResponseDesl(ntlm_hash, session_hash.a, ntlm_response); | |
118 } | |
119 | |
120 void GenerateResponsesV1WithSS(const base::string16& password, | |
121 const uint8_t* server_challenge, | |
122 const uint8_t* client_challenge, | |
123 uint8_t* lm_response, | |
124 uint8_t* ntlm_response) { | |
125 GenerateLMResponseV1WithSS(client_challenge, lm_response); | |
126 GenerateNtlmResponseV1WithSS(password, server_challenge, client_challenge, | |
127 ntlm_response); | |
128 } | |
129 | |
130 } // namespace ntlm | |
131 } // namespace net | |
OLD | NEW |