Skip to content

Commit

Permalink
Add OSCryptAsync - an async version of OSCrypt.
Browse files Browse the repository at this point in the history
In order to support initialization that might take a longer time
to complete, e.g. App-Bound encryption, this CL adds an
OSCrypt asynchronous implementation.

This CL implements the skeleton functionality for obtaining
an Encryptor instance using the `GetInstance` method
along with tests that verify compatibility with OSCrypt's sync
interface.

Once obtained, a thread-safe Encryptor object can be used for
encryption and decryption.

For now, all calls to the Encrypt and Decrypt methods on the
instance of Encryptor pass through to the sync version of
OSCrypt.

This CL also moves OWNERS and DIR_METADATA back from the 'sync'
subdirectory to the parent, after being inadvertently moved in
https://crrev.com/c/4336304, and creates some small READMEs
for the interfaces.

Future CLs will add real async, provider support, a DPAPI provider,
mojo multi-process support and integration into src/content and
src/chrome.

BUG=1373092

Change-Id: If495fe9bf4fab0cdcb4abc14826bb6d4eaed36cf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3943468
Commit-Queue: Will Harris <wfh@chromium.org>
Reviewed-by: Ted Choc <tedchoc@chromium.org>
Reviewed-by: Christos Froussios <cfroussios@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1117558}
  • Loading branch information
Will Harris authored and Chromium LUCI CQ committed Mar 15, 2023
1 parent 654071e commit e6e9d25
Show file tree
Hide file tree
Showing 16 changed files with 610 additions and 0 deletions.
1 change: 1 addition & 0 deletions components/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ test("components_unittests") {
"//components/open_from_clipboard:unit_tests",
"//components/openscreen_platform:unittests",
"//components/optimization_guide/core:unit_tests",
"//components/os_crypt/async/browser:unit_tests",
"//components/os_crypt/sync:unit_tests",
"//components/password_manager/core/browser:unit_tests",
"//components/payments/core:unit_tests",
Expand Down
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions components/os_crypt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
***OS Crypt***

This directory contains `OSCrypt` implementations that support cryptographic
primitives that allow binding data to the OS user.

There are two implementations, a [sync](sync) interface which can be called on
any thread, and an [async](async) interface that is instance based.

The [async](async) interface is currently under construction and so all current
usage should go via the [sync](sync) interface.

Please see the README.md in those directories for more information on each
implementation.
2 changes: 2 additions & 0 deletions components/os_crypt/async/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Also, feel free to use components/os_crypt/OWNERS.
wfh@chromium.org
27 changes: 27 additions & 0 deletions components/os_crypt/async/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
***OS Crypt Async***

This directory contains the new version of `OSCrypt` that supports asynchronous
initialization and pluggable providers.

**Main interfaces**

`browser/` should only be included by code that lives in the browser process. An
instance of `OSCryptAsync` should be constructed and held in browser and is
responsible for minting `Encryptor` instances.

`GetInstance` can be called as many times as necessary to obtain instances of
`Encryptor` that should be used for encryption operations. Note that
`GetInstance` returns a `base::CallbackListSubscription` whose destruction will
cause the callback to never run. This should be stored with the same lifetime as
the callback to ensure correct function. See documentation for
`base::CallbackList` for more on this.

`common/` can be included by any code in any process and allows `Encryptor`
instances to perform encrypt/decrypt operations. These `EncryptString` and
`DecryptString` operations are sync and can be called on any thread, the same as
with legacy `os_crypt::OSCrypt`.

It is preferred to use the `base::span` `EncryptData` and `DecryptData` APIs,
however the `EncryptString` and `DecryptString` APIs are provided for ease of
compatibility with existing callers of `os_crypt::OSCrypt`. The string and span
APIs are compatible with one another.
35 changes: 35 additions & 0 deletions components/os_crypt/async/browser/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 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.

component("browser") {
sources = [
"os_crypt_async.cc",
"os_crypt_async.h",
]

public_deps = [
"//base",
"//components/os_crypt/async/common",
]

defines = [ "IS_OS_CRYPT_ASYNC_IMPL" ]
}

source_set("unit_tests") {
testonly = true
sources = [ "os_crypt_async_unittest.cc" ]
deps = [
":browser",
"//base",
"//base/test:test_support",
"//components/os_crypt/async/common",
"//components/os_crypt/sync",
"//components/os_crypt/sync:test_support",
"//testing/gtest",
]

if (is_win) {
libs = [ "crypt32.lib" ]
}
}
3 changes: 3 additions & 0 deletions components/os_crypt/async/browser/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_rules = [
"+components/os_crypt/sync",
]
34 changes: 34 additions & 0 deletions components/os_crypt/async/browser/os_crypt_async.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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 "base/callback_list.h"
#include "base/sequence_checker.h"
#include "base/types/pass_key.h"
#include "components/os_crypt/async/common/encryptor.h"

namespace os_crypt_async {

OSCryptAsync::OSCryptAsync() = default;
OSCryptAsync::~OSCryptAsync() = default;

OSCryptAsync::OSCryptAsync(OSCryptAsync&& other) = default;
OSCryptAsync& OSCryptAsync::operator=(OSCryptAsync&& other) = default;

base::CallbackListSubscription OSCryptAsync::GetInstance(
InitCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

if (!is_initialized_) {
encryptor_instance_ =
std::make_unique<Encryptor>(/*passkey=*/base::PassKey<OSCryptAsync>());
is_initialized_ = true;
}

std::move(callback).Run(encryptor_instance_->Clone(), true);
return base::CallbackListSubscription();
}

} // namespace os_crypt_async
54 changes: 54 additions & 0 deletions components/os_crypt/async/browser/os_crypt_async.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.

#ifndef COMPONENTS_OS_CRYPT_ASYNC_BROWSER_OS_CRYPT_ASYNC_H_
#define COMPONENTS_OS_CRYPT_ASYNC_BROWSER_OS_CRYPT_ASYNC_H_

#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/sequence_checker.h"
#include "components/os_crypt/async/common/encryptor.h"

namespace os_crypt_async {

// This class is responsible for vending Encryptor instances.
class COMPONENT_EXPORT(OS_CRYPT_ASYNC) OSCryptAsync {
public:
using InitCallback = base::OnceCallback<void(Encryptor, bool result)>;

// TODO(crbug.com/1373092): add configuration parameters here, and a
// UIThreadRunner parameter.
OSCryptAsync();
~OSCryptAsync();

// Moveable, not copyable.
OSCryptAsync(OSCryptAsync&& other);
OSCryptAsync& operator=(OSCryptAsync&& other);
OSCryptAsync(const OSCryptAsync&) = delete;
OSCryptAsync& operator=(const OSCryptAsync&) = delete;

// Obtain an Encryptor instance. Can be called multiple times, each one will
// get a valid instance once the initialization has completed, on the
// `callback`. Must be called on the same sequence that the OSCryptAsync
// object was created on. Destruction of the `base::CallbackListSubscription`
// will cause the callback not to run, see `base/callback_list.h`.
//
// TODO(crbug.com/1373092): This function is currently sync, but will be made
// async in a future CL.
[[nodiscard]] base::CallbackListSubscription GetInstance(
InitCallback callback);

private:
std::unique_ptr<Encryptor> GUARDED_BY_CONTEXT(sequence_checker_)
encryptor_instance_;

bool is_initialized_ GUARDED_BY_CONTEXT(sequence_checker_) = false;

SEQUENCE_CHECKER(sequence_checker_);
};

} // namespace os_crypt_async

#endif // COMPONENTS_OS_CRYPT_ASYNC_BROWSER_OS_CRYPT_ASYNC_H_

0 comments on commit e6e9d25

Please sign in to comment.