File: os_crypt_async_browsertest.cc

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (145 lines) | stat: -rw-r--r-- 5,425 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/os_crypt/async/browser/os_crypt_async.h"

#include <memory>
#include <optional>
#include <vector>

#include "base/functional/bind.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_future.h"
#include "chrome/browser/browser_process.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/os_crypt/async/browser/test_utils.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "components/os_crypt/sync/os_crypt.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/test/browser_test.h"
#include "services/test/echo/public/mojom/echo.mojom.h"

namespace os_crypt_async {

namespace {

Encryptor GetInstanceSync(OSCryptAsync& factory,
                          Encryptor::Option option = Encryptor::Option::kNone) {
  base::RunLoop run_loop;
  std::optional<Encryptor> encryptor;
  auto sub = factory.GetInstance(
      base::BindLambdaForTesting([&](Encryptor instance, bool result) {
        EXPECT_TRUE(result);
        encryptor.emplace(std::move(instance));
        run_loop.Quit();
      }),
      option);
  run_loop.Run();
  return std::move(*encryptor);
}

}  // namespace

class OSCryptAsyncBrowserTest : public InProcessBrowserTest {
 protected:
  base::HistogramTester histogram_tester_;
};

// Test the basic browser interface to Encrypt and Decrypt data.
IN_PROC_BROWSER_TEST_F(OSCryptAsyncBrowserTest, EncryptDecrypt) {
  auto encryptor = GetInstanceSync(*g_browser_process->os_crypt_async());
  // These histograms should always have been recorded by the time the
  // GetInstance callback above has happened, since the browser registers its
  // metrics callback before anything else gets a chance to.
  histogram_tester_.ExpectTotalCount("OSCrypt.AsyncInitialization.Time", 1u);
  histogram_tester_.ExpectUniqueSample("OSCrypt.AsyncInitialization.Result",
                                       true, 1u);

  auto ciphertext = encryptor.EncryptString("plaintext");
  ASSERT_TRUE(ciphertext);

  auto decrypted = encryptor.DecryptData(*ciphertext);
  ASSERT_TRUE(decrypted);

  EXPECT_EQ(*decrypted, "plaintext");
}

// This test verifies that an Encryptor works inside a fully sandboxed process.
IN_PROC_BROWSER_TEST_F(OSCryptAsyncBrowserTest, SandboxedEncryptionTest) {
  // Use a testing instance, otherwise fallback to os_crypt sync does not work
  // on all platforms when inside a sandbox without transferring the key over
  // manually.
  auto os_crypt_async = GetTestOSCryptAsyncForTesting();
  Encryptor encryptor = GetInstanceSync(*os_crypt_async);

  constexpr char kTestData[] = "testdatatest";
  // First, encrypt the data.
  const auto encrypted_data = encryptor.EncryptString(kTestData);
  ASSERT_TRUE(encrypted_data.has_value());

  // Launch sandboxed echo service.
  auto echo_service =
      content::ServiceProcessHost::Launch<echo::mojom::EchoService>();

  base::test::TestFuture<std::optional<std::vector<uint8_t>>> future;

  // This performs a decrypt, then an encrypt.
  echo_service->DecryptEncrypt(
      std::move(encryptor), *encrypted_data,
      future.GetCallback<const std::optional<std::vector<uint8_t>>&>());
  auto& result = future.Get();
  ASSERT_TRUE(result.has_value());

  // Obtain a second encryptor, since the first one was consumed in the mojo
  // call above.
  Encryptor encryptor2 = GetInstanceSync(*os_crypt_async);
  // Finally, decrypt the data again.
  const auto plaintext = encryptor2.DecryptData(*result);
  ASSERT_TRUE(plaintext.has_value());
  EXPECT_EQ(*plaintext, kTestData);
}

// This test verifies that an Encryptor obtained with the kEncryptSyncCompat
// option encrypts data that can be decrypted by OSCrypt, as well as ensuring
// that kEncryptSyncCompat and kNone options are interoperable with each other.
IN_PROC_BROWSER_TEST_F(OSCryptAsyncBrowserTest, OSCryptBackwardsCompatTest) {
  auto encryptor = GetInstanceSync(*g_browser_process->os_crypt_async(),
                                   Encryptor::Option::kEncryptSyncCompat);
  auto ciphertext = encryptor.EncryptString("plaintext");
  ASSERT_TRUE(ciphertext);

  {
    const auto decrypted = encryptor.DecryptData(*ciphertext);
    ASSERT_TRUE(decrypted);
    EXPECT_EQ(*decrypted, "plaintext");
  }

  {
    std::string decrypted;
    ASSERT_TRUE(OSCrypt::DecryptString(
        std::string(ciphertext->begin(), ciphertext->end()), &decrypted));
    EXPECT_EQ(decrypted, "plaintext");
  }

  {
    // Verify that data encrypted from a kEncryptSyncCompat encryptor can be
    // decrypted with a kNone encryptor.
    auto full_encryptor = GetInstanceSync(*g_browser_process->os_crypt_async(),
                                          Encryptor::Option::kNone);
    const auto decrypted = full_encryptor.DecryptData(*ciphertext);
    ASSERT_TRUE(decrypted);
    EXPECT_EQ(decrypted, "plaintext");

    // Verify that data encrypted from a kNone encryptor can be decrypted with a
    // kEncryptSyncCompat encryptor.
    const auto ciphertext2 = full_encryptor.EncryptString("more_plaintext");
    ASSERT_TRUE(ciphertext2);
    const auto decrypted2 = encryptor.DecryptData(*ciphertext2);
    ASSERT_TRUE(decrypted2);
    EXPECT_EQ(*decrypted2, "more_plaintext");
  }
}

}  // namespace os_crypt_async