Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(245)

Side by Side Diff: net/http/ntlm_client.cc

Issue 2879353002: Add a buffer reader/writer for NTLM. (Closed)
Patch Set: Add a buffer reader/writer for NTLM. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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/base/zap.h"
12 #include "net/http/des.h"
13 #include "net/http/md4.h"
14 #include "net/http/ntlm_buffer_writer.h"
15
16 namespace net {
17
18 NtlmClient::NtlmClient(uint32_t negotiate_flags)
19 : negotiate_flags_(negotiate_flags) {
20 // Just generate the negotiate message once and hold on to it. It never
21 // changes and in a NTLMv2 it's used as an input
22 // to the Message Integrity Check in the Authenticate message.
23 GenerateNegotiateMessage();
24 }
25
26 NtlmClient::~NtlmClient() {}
27
28 void NtlmClient::GenerateNtlmHashV1(const base::string16& password,
29 uint8_t* hash) {
30 // hash param must have at least 16 bytes of space.
31 NtlmBufferWriter writer(password.length() * 2);
32
33 // The writer will handle the big endian case if necessary.
34 writer.WriteUnicodeString(password);
35 weak_crypto::MD4Sum(writer.GetBufferPtr(), writer.GetLength(), hash);
36 ZapBuf(writer.GetBufferPtr(), writer.GetLength());
37 }
38
39 void NtlmClient::GenerateResponseDesl(const uint8_t* hash,
40 const uint8_t* challenge,
41 uint8_t* response) {
42 // hash param must be 16 bytes.
43 // challenge param must be 8 bytes.
44 // response param must be at least 24 bytes.
45
46 // See DESL(K, D) function in Section 6 Appendix A of NTLMSSP specification.
47 uint8_t key1[8];
48 uint8_t key2[8];
49 uint8_t key3[8];
50
51 // The last 2 bytes of the hash are zero padded (5 zeros) as the
52 // input to generate key3.
53 uint8_t padded_hash[7];
54 padded_hash[0] = hash[14];
55 padded_hash[1] = hash[15];
56 memset(padded_hash + 2, 0, 5);
57
58 DESMakeKey(hash, key1);
59 DESMakeKey(hash + 7, key2);
60 DESMakeKey(padded_hash, key3);
61
62 DESEncrypt(key1, challenge, response);
63 DESEncrypt(key2, challenge, response + 8);
64 DESEncrypt(key3, challenge, response + 16);
65 }
66
67 void NtlmClient::GenerateNtlmResponseV1(const base::string16& password,
68 const uint8_t* challenge,
69 uint8_t* ntlm_response) {
70 uint8_t ntlm_hash[NtlmMessage::NTLM_HASH_LEN];
71 GenerateNtlmHashV1(password, ntlm_hash);
72 GenerateResponseDesl(ntlm_hash, challenge, ntlm_response);
73 }
74
75 void NtlmClient::GenerateResponsesV1(const base::string16& password,
76 const uint8_t* server_challenge,
77 uint8_t* lm_response,
78 uint8_t* ntlm_response) {
79 GenerateNtlmResponseV1(password, server_challenge, ntlm_response);
80
81 // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the
82 // same. So just copy the ntlm_response into the lm_response.
83 memcpy(lm_response, ntlm_response, NtlmMessage::RESPONSE_V1_LEN);
84 }
85
86 void NtlmClient::GenerateLMResponseV1WithSS(const uint8_t* client_challenge,
87 uint8_t* lm_response) {
88 // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of
89 // client challenge and 16 bytes of zeros. (See 3.3.1)
90 memcpy(lm_response, client_challenge, NtlmMessage::CHALLENGE_LEN);
91 memset(lm_response + NtlmMessage::CHALLENGE_LEN, 0,
92 NtlmMessage::RESPONSE_V1_LEN - NtlmMessage::CHALLENGE_LEN);
93 }
94
95 void NtlmClient::GenerateSessionHashV1WithSS(const uint8_t* server_challenge,
96 const uint8_t* client_challenge,
97 base::MD5Digest* session_hash) {
98 base::MD5Context ctx;
99 base::MD5Init(&ctx);
100 base::MD5Update(
101 &ctx, base::StringPiece(reinterpret_cast<const char*>(server_challenge),
102 NtlmMessage::CHALLENGE_LEN));
103 base::MD5Update(
104 &ctx, base::StringPiece(reinterpret_cast<const char*>(client_challenge),
105 NtlmMessage::CHALLENGE_LEN));
106
107 base::MD5Final(session_hash, &ctx);
108 }
109
110 void NtlmClient::GenerateNtlmResponseV1WithSS(const base::string16& password,
111 const uint8_t* server_challenge,
112 const uint8_t* client_challenge,
113 uint8_t* ntlm_response) {
114 // Generate the NTLMv1 Hash.
115 uint8_t ntlm_hash[NtlmMessage::NTLM_HASH_LEN];
116 GenerateNtlmHashV1(password, ntlm_hash);
117
118 // Generate the NTLMv1 Session Hash.
119 base::MD5Digest session_hash;
120 GenerateSessionHashV1WithSS(server_challenge, client_challenge,
121 &session_hash);
122
123 // Only the first 8 bytes of |session_hash.a| are actually used.
124 GenerateResponseDesl(ntlm_hash, session_hash.a, ntlm_response);
125 }
126
127 void NtlmClient::GenerateResponsesV1WithSS(const base::string16& password,
128 const uint8_t* server_challenge,
129 const uint8_t* client_challenge,
130 uint8_t* lm_response,
131 uint8_t* ntlm_response) {
132 GenerateLMResponseV1WithSS(client_challenge, lm_response);
133 GenerateNtlmResponseV1WithSS(password, server_challenge, client_challenge,
134 ntlm_response);
135 }
136
137 void NtlmClient::GenerateNegotiateMessage() {
138 NtlmBufferWriter writer(NtlmMessage::NEGOTIATE_MESSAGE_LEN);
139 bool result = writer.WriteMessageHeader(NtlmMessage::MESSAGE_NEGOTIATE) &&
140 writer.WriteUInt32(negotiate_flags_) &&
141 writer.WriteEmptySecurityBuffer() &&
142 writer.WriteEmptySecurityBuffer() && writer.IsEndOfBuffer();
143
144 DCHECK(result);
145
146 negotiate_message_.reset(writer.ReleaseBufferPtr());
147 }
148
149 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698