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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: net/http/ntlm_client.cc
diff --git a/net/http/ntlm_client.cc b/net/http/ntlm_client.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a39e29c97873ff17b036d4f7aa96d2eab3906635
--- /dev/null
+++ b/net/http/ntlm_client.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/ntlm_client.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "net/base/zap.h"
+#include "net/http/des.h"
+#include "net/http/md4.h"
+#include "net/http/ntlm_buffer_writer.h"
+
+namespace net {
+
+namespace ntlm {
+
+void GenerateNtlmHashV1(const base::string16& password, uint8_t* hash) {
+ size_t length = password.length() * 2;
+ // hash param must have at least 16 bytes of space.
+ NtlmBufferWriter writer(length);
+
+ // The writer will handle the big endian case if necessary.
+ writer.WriteUnicodeString(password);
+
+ std::unique_ptr<uint8_t[]> buffer(writer.ReleaseBufferPtr());
+
+ weak_crypto::MD4Sum(buffer.get(), length, hash);
+ 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.
+}
+
+void GenerateResponseDesl(const uint8_t* hash,
+ const uint8_t* challenge,
+ uint8_t* response) {
+ // hash param must be 16 bytes.
+ // challenge param must be 8 bytes.
+ // response param must be at least 24 bytes.
+
+ // See DESL(K, D) function in Section 6 Appendix A of NTLMSSP specification.
+ 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)
+ uint8_t key2[8];
+ uint8_t key3[8];
+
+ // The last 2 bytes of the hash are zero padded (5 zeros) as the
+ // input to generate key3.
+ uint8_t padded_hash[7];
+ padded_hash[0] = hash[14];
+ padded_hash[1] = hash[15];
+ memset(padded_hash + 2, 0, 5);
+
+ DESMakeKey(hash, key1);
+ DESMakeKey(hash + 7, key2);
+ DESMakeKey(padded_hash, key3);
+
+ DESEncrypt(key1, challenge, response);
+ DESEncrypt(key2, challenge, response + 8);
+ DESEncrypt(key3, challenge, response + 16);
+}
+
+void GenerateNtlmResponseV1(const base::string16& password,
+ const uint8_t* challenge,
+ uint8_t* ntlm_response) {
+ uint8_t ntlm_hash[ntlm::NTLM_HASH_LEN];
+ GenerateNtlmHashV1(password, ntlm_hash);
+ GenerateResponseDesl(ntlm_hash, challenge, ntlm_response);
+}
+
+void GenerateResponsesV1(const base::string16& password,
+ const uint8_t* server_challenge,
+ uint8_t* lm_response,
+ uint8_t* ntlm_response) {
+ GenerateNtlmResponseV1(password, server_challenge, ntlm_response);
+
+ // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the
+ // same. So just copy the ntlm_response into the lm_response.
+ memcpy(lm_response, ntlm_response, ntlm::RESPONSE_V1_LEN);
+}
+
+void GenerateLMResponseV1WithSS(const uint8_t* client_challenge,
+ uint8_t* lm_response) {
+ // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of
+ // client challenge and 16 bytes of zeros. (See 3.3.1)
+ memcpy(lm_response, client_challenge, ntlm::CHALLENGE_LEN);
+ memset(lm_response + ntlm::CHALLENGE_LEN, 0,
+ ntlm::RESPONSE_V1_LEN - ntlm::CHALLENGE_LEN);
+}
+
+void GenerateSessionHashV1WithSS(const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ base::MD5Digest* session_hash) {
+ base::MD5Context ctx;
+ base::MD5Init(&ctx);
+ base::MD5Update(
+ &ctx, base::StringPiece(reinterpret_cast<const char*>(server_challenge),
+ ntlm::CHALLENGE_LEN));
+ base::MD5Update(
+ &ctx, base::StringPiece(reinterpret_cast<const char*>(client_challenge),
+ ntlm::CHALLENGE_LEN));
+
+ base::MD5Final(session_hash, &ctx);
+}
+
+void GenerateNtlmResponseV1WithSS(const base::string16& password,
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ uint8_t* ntlm_response) {
+ // Generate the NTLMv1 Hash.
+ uint8_t ntlm_hash[ntlm::NTLM_HASH_LEN];
+ GenerateNtlmHashV1(password, ntlm_hash);
+
+ // Generate the NTLMv1 Session Hash.
+ base::MD5Digest session_hash;
+ GenerateSessionHashV1WithSS(server_challenge, client_challenge,
+ &session_hash);
+
+ // Only the first 8 bytes of |session_hash.a| are actually used.
+ GenerateResponseDesl(ntlm_hash, session_hash.a, ntlm_response);
+}
+
+void GenerateResponsesV1WithSS(const base::string16& password,
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ uint8_t* lm_response,
+ uint8_t* ntlm_response) {
+ GenerateLMResponseV1WithSS(client_challenge, lm_response);
+ GenerateNtlmResponseV1WithSS(password, server_challenge, client_challenge,
+ ntlm_response);
+}
+
+} // namespace ntlm
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698