Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |