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

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

Issue 2873673002: Add unit tests for NTLMv1 portable implementation (Closed)
Patch Set: Add unit tests for existing NTLM portable code. 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 namespace ntlm {
19
20 void GenerateNtlmHashV1(const base::string16& password, uint8_t* hash) {
21 size_t length = password.length() * 2;
22 // hash param must have at least 16 bytes of space.
23 NtlmBufferWriter writer(length);
24
25 // The writer will handle the big endian case if necessary.
26 writer.WriteUnicodeString(password);
27
28 std::unique_ptr<uint8_t[]> buffer(writer.ReleaseBufferPtr());
29
30 weak_crypto::MD4Sum(buffer.get(), length, hash);
31 ZapBuf(buffer.get(), length);
Ryan Sleevi 2017/06/08 18:47:43 https://codereview.chromium.org/2926333002/ :)
zentaro 2017/06/12 23:16:54 Done.
32 }
33
34 void GenerateResponseDesl(const uint8_t* hash,
35 const uint8_t* challenge,
36 uint8_t* response) {
37 // hash param must be 16 bytes.
38 // challenge param must be 8 bytes.
39 // response param must be at least 24 bytes.
40
41 // See DESL(K, D) function in Section 6 Appendix A of NTLMSSP specification.
42 uint8_t key1[8];
Ryan Sleevi 2017/06/08 18:47:43 Should we = {0}; these to ensure they're all zero-
zentaro 2017/06/12 23:16:54 I assumed it wasn't necessary since we do (should)
43 uint8_t key2[8];
44 uint8_t key3[8];
45
46 // The last 2 bytes of the hash are zero padded (5 zeros) as the
47 // input to generate key3.
48 uint8_t padded_hash[7];
49 padded_hash[0] = hash[14];
50 padded_hash[1] = hash[15];
51 memset(padded_hash + 2, 0, 5);
52
53 DESMakeKey(hash, key1);
54 DESMakeKey(hash + 7, key2);
55 DESMakeKey(padded_hash, key3);
56
57 DESEncrypt(key1, challenge, response);
58 DESEncrypt(key2, challenge, response + 8);
59 DESEncrypt(key3, challenge, response + 16);
60 }
61
62 void GenerateNtlmResponseV1(const base::string16& password,
63 const uint8_t* challenge,
64 uint8_t* ntlm_response) {
65 uint8_t ntlm_hash[ntlm::NTLM_HASH_LEN];
66 GenerateNtlmHashV1(password, ntlm_hash);
67 GenerateResponseDesl(ntlm_hash, challenge, ntlm_response);
68 }
69
70 void GenerateResponsesV1(const base::string16& password,
71 const uint8_t* server_challenge,
72 uint8_t* lm_response,
73 uint8_t* ntlm_response) {
74 GenerateNtlmResponseV1(password, server_challenge, ntlm_response);
75
76 // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the
77 // same. So just copy the ntlm_response into the lm_response.
78 memcpy(lm_response, ntlm_response, ntlm::RESPONSE_V1_LEN);
79 }
80
81 void GenerateLMResponseV1WithSS(const uint8_t* client_challenge,
82 uint8_t* lm_response) {
83 // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of
84 // client challenge and 16 bytes of zeros. (See 3.3.1)
85 memcpy(lm_response, client_challenge, ntlm::CHALLENGE_LEN);
86 memset(lm_response + ntlm::CHALLENGE_LEN, 0,
87 ntlm::RESPONSE_V1_LEN - ntlm::CHALLENGE_LEN);
88 }
89
90 void GenerateSessionHashV1WithSS(const uint8_t* server_challenge,
91 const uint8_t* client_challenge,
92 base::MD5Digest* session_hash) {
93 base::MD5Context ctx;
94 base::MD5Init(&ctx);
95 base::MD5Update(
96 &ctx, base::StringPiece(reinterpret_cast<const char*>(server_challenge),
97 ntlm::CHALLENGE_LEN));
98 base::MD5Update(
99 &ctx, base::StringPiece(reinterpret_cast<const char*>(client_challenge),
100 ntlm::CHALLENGE_LEN));
101
102 base::MD5Final(session_hash, &ctx);
103 }
104
105 void GenerateNtlmResponseV1WithSS(const base::string16& password,
106 const uint8_t* server_challenge,
107 const uint8_t* client_challenge,
108 uint8_t* ntlm_response) {
109 // Generate the NTLMv1 Hash.
110 uint8_t ntlm_hash[ntlm::NTLM_HASH_LEN];
111 GenerateNtlmHashV1(password, ntlm_hash);
112
113 // Generate the NTLMv1 Session Hash.
114 base::MD5Digest session_hash;
115 GenerateSessionHashV1WithSS(server_challenge, client_challenge,
116 &session_hash);
117
118 // Only the first 8 bytes of |session_hash.a| are actually used.
119 GenerateResponseDesl(ntlm_hash, session_hash.a, ntlm_response);
120 }
121
122 void GenerateResponsesV1WithSS(const base::string16& password,
123 const uint8_t* server_challenge,
124 const uint8_t* client_challenge,
125 uint8_t* lm_response,
126 uint8_t* ntlm_response) {
127 GenerateLMResponseV1WithSS(client_challenge, lm_response);
128 GenerateNtlmResponseV1WithSS(password, server_challenge, client_challenge,
129 ntlm_response);
130 }
131
132 } // namespace ntlm
133 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698