1 // Copyright 2019 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 "components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h"
6
7 #include "base/test/mock_callback.h"
8 #include "base/test/task_environment.h"
9 #include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
10 #include "components/password_manager/core/browser/leak_detection/single_lookup_response.h"
11 #include "crypto/sha2.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace password_manager {
16 namespace {
17
18 using ::testing::ElementsAre;
19 using ::testing::Field;
20
21 // Converts a string to an array for printing.
StringToArray(const std::string & s)22 std::vector<int> StringToArray(const std::string& s) {
23 return std::vector<int>(s.begin(), s.end());
24 }
25
26 } // namespace
27
TEST(LeakDetectionRequestUtils,PrepareSingleLeakRequestData)28 TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestData) {
29 base::test::TaskEnvironment task_env;
30 base::MockCallback<SingleLeakRequestDataCallback> callback;
31
32 PrepareSingleLeakRequestData("jonsnow", "1234", callback.Get());
33 EXPECT_CALL(
34 callback,
35 Run(AllOf(
36 Field(&LookupSingleLeakData::payload,
37 AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
38 ElementsAre(0x3D, 0x70, 0xD3, 0x60)),
39 Field(&LookupSingleLeakPayload::encrypted_payload,
40 testing::Ne("")))),
41 Field(&LookupSingleLeakData::encryption_key, testing::Ne("")))));
42 task_env.RunUntilIdle();
43 }
44
TEST(LeakDetectionRequestUtils,PrepareSingleLeakRequestDataWithKey)45 TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestDataWithKey) {
46 base::test::SingleThreadTaskEnvironment task_env;
47 auto task_runner = task_env.GetMainThreadTaskRunner();
48 base::CancelableTaskTracker task_tracker;
49 base::MockOnceCallback<void(LookupSingleLeakPayload)> callback;
50
51 PrepareSingleLeakRequestData(task_tracker, *task_runner, "random_key",
52 "jonsnow", "1234", callback.Get());
53 EXPECT_CALL(callback,
54 Run(AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
55 ElementsAre(0x3D, 0x70, 0xD3, 0x60)),
56 Field(&LookupSingleLeakPayload::encrypted_payload,
57 testing::Ne("")))));
58 task_env.RunUntilIdle();
59 }
60
TEST(LeakDetectionRequestUtils,PrepareSingleLeakRequestDataCancelled)61 TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestDataCancelled) {
62 base::test::SingleThreadTaskEnvironment task_env;
63 auto task_runner = task_env.GetMainThreadTaskRunner();
64 base::MockOnceCallback<void(LookupSingleLeakPayload)> callback;
65 EXPECT_CALL(callback, Run).Times(0);
66
67 {
68 base::CancelableTaskTracker task_tracker;
69 PrepareSingleLeakRequestData(task_tracker, *task_runner, "random_key",
70 "jonsnow", "1234", callback.Get());
71 }
72
73 task_env.RunUntilIdle();
74 }
75
TEST(LeakDetectionRequestUtils,AnalyzeResponseResult_DecryptionError)76 TEST(LeakDetectionRequestUtils, AnalyzeResponseResult_DecryptionError) {
77 base::test::TaskEnvironment task_env;
78
79 // Force a decryption error by returning trash bytes.
80 auto response = std::make_unique<SingleLookupResponse>();
81 response->reencrypted_lookup_hash = "trash_bytes";
82
83 base::MockCallback<SingleLeakResponseAnalysisCallback> callback;
84 AnalyzeResponse(std::move(response), "random_key", callback.Get());
85 EXPECT_CALL(callback, Run(AnalyzeResponseResult::kDecryptionError));
86 task_env.RunUntilIdle();
87 }
88
TEST(LeakDetectionRequestUtils,AnalyzeResponseResult_NoLeak)89 TEST(LeakDetectionRequestUtils, AnalyzeResponseResult_NoLeak) {
90 base::test::TaskEnvironment task_env;
91
92 constexpr char kUsernamePasswordHash[] = "abcdefg";
93 auto response = std::make_unique<SingleLookupResponse>();
94 std::string key_client;
95 std::string encrypted_username_password =
96 CipherEncrypt(kUsernamePasswordHash, &key_client);
97 std::string key_server;
98 response->reencrypted_lookup_hash =
99 CipherReEncrypt(encrypted_username_password, &key_server);
100 SCOPED_TRACE(testing::Message()
101 << "key_client="
102 << testing::PrintToString(StringToArray(key_client))
103 << ", key_server="
104 << testing::PrintToString(StringToArray(key_server)));
105
106 response->encrypted_leak_match_prefixes.push_back(crypto::SHA256HashString(
107 CipherEncryptWithKey("unrelated_trash", key_server)));
108
109 base::MockCallback<SingleLeakResponseAnalysisCallback> callback;
110 AnalyzeResponse(std::move(response), key_client, callback.Get());
111 EXPECT_CALL(callback, Run(AnalyzeResponseResult::kNotLeaked));
112 task_env.RunUntilIdle();
113 }
114
TEST(LeakDetectionRequestUtils,AnalyzeResponseResult_Leak)115 TEST(LeakDetectionRequestUtils, AnalyzeResponseResult_Leak) {
116 base::test::TaskEnvironment task_env;
117
118 constexpr char kUsernamePasswordHash[] = "abcdefg";
119 auto response = std::make_unique<SingleLookupResponse>();
120 std::string key_client;
121 std::string encrypted_username_password =
122 CipherEncrypt(kUsernamePasswordHash, &key_client);
123 std::string key_server;
124 response->reencrypted_lookup_hash =
125 CipherReEncrypt(encrypted_username_password, &key_server);
126 SCOPED_TRACE(testing::Message()
127 << "key_client="
128 << testing::PrintToString(StringToArray(key_client))
129 << ", key_server="
130 << testing::PrintToString(StringToArray(key_server)));
131
132 // Random length of the prefix for values in |encrypted_leak_match_prefixes|.
133 // The server can pick any value.
134 constexpr int kPrefixLength = 30;
135 response->encrypted_leak_match_prefixes.push_back(crypto::SHA256HashString(
136 CipherEncryptWithKey("unrelated_trash", key_server)));
137 response->encrypted_leak_match_prefixes.push_back(
138 crypto::SHA256HashString(
139 CipherEncryptWithKey(kUsernamePasswordHash, key_server))
140 .substr(0, kPrefixLength));
141
142 base::MockCallback<SingleLeakResponseAnalysisCallback> callback;
143
144 AnalyzeResponse(std::move(response), key_client, callback.Get());
145 EXPECT_CALL(callback, Run(AnalyzeResponseResult::kLeaked));
146 task_env.RunUntilIdle();
147 }
148
149 } // namespace password_manager
150