Commit 34e2627e authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

sessions: adds support for encryption

Encryption is done at the command level. Specifically, when encrypted
each command is written as a length (not encrypted) followed by the
encrypted command-id and command-contents pair.

BUG=1033924
TEST=component_unittests CommandStorageBackend*

Change-Id: I4899b6daefba85ef3ae865262b375ad345341c63
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2017981Reviewed-by: default avatarAdam Langley <agl@chromium.org>
Commit-Queue: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735963}
parent 57e438bc
......@@ -138,6 +138,7 @@ source_set("shared") {
"//components/prefs",
"//components/tab_groups",
"//components/variations",
"//crypto",
"//skia",
"//ui/base",
"//ui/gfx",
......@@ -182,6 +183,7 @@ source_set("unit_tests") {
}
testonly = true
sources = [
"core/command_storage_backend_unittest.cc",
"core/serialized_navigation_entry_unittest.cc",
"core/session_id_generator_unittest.cc",
"core/snapshotting_session_backend_unittest.cc",
......
include_rules = [
"+components/history/core/common",
"+components/variations",
"+crypto",
"+ui/base",
"+ui/gfx",
]
......@@ -21,6 +21,10 @@ namespace base {
class File;
}
namespace crypto {
class Aead;
}
namespace sessions {
// CommandStorageBackend is the backend used by CommandStorageManager. It writes
......@@ -39,6 +43,9 @@ class SESSIONS_EXPORT CommandStorageBackend
// for testing.
static const int kFileReadBufferSize;
// Number of bytes encryption adds.
static const size_type kEncryptionOverheadInBytes;
// Creates a CommandStorageBackend. This method is invoked on the MAIN thread,
// and does no IO. The real work is done from Init, which is invoked on
// a background task runer.
......@@ -54,15 +61,18 @@ class SESSIONS_EXPORT CommandStorageBackend
}
// Appends the specified commands to the current file. If |truncate| is true
// the file is truncated.
// the file is truncated. If |truncate| is true and |crypto_key| is non-empty,
// then all commands are encrypted using the supplied key.
void AppendCommands(
std::vector<std::unique_ptr<sessions::SessionCommand>> commands,
bool truncate);
bool truncate,
const std::vector<uint8_t>& crypto_key = std::vector<uint8_t>());
// Invoked from the service to read the commands that make up the last
// session, invokes ReadLastSessionCommandsImpl to do the work.
// Reads the commands that make up the current session. If |crypto_key|
// is non-empty, it is used to decrypt the file.
void ReadCurrentSessionCommands(
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
const std::vector<uint8_t>& crypto_key,
GetCommandsCallback callback);
bool inited() const { return inited_; }
......@@ -79,12 +89,12 @@ class SESSIONS_EXPORT CommandStorageBackend
const base::FilePath& path() const { return path_; }
// Reads the commands from the current file.
//
// On success, the read commands are added to commands. It is up to the
// caller to delete the commands.
// Reads the commands from the specified file. If |crypto_key| is non-empty,
// it is used to decrypt the file. On success, the read commands are added to
// |commands|.
bool ReadCommandsFromFile(
const base::FilePath& path,
const std::vector<uint8_t>& crypto_key,
std::vector<std::unique_ptr<sessions::SessionCommand>>* commands);
// Closes the file. The next time AppendCommands() is called the file will
......@@ -112,6 +122,19 @@ class SESSIONS_EXPORT CommandStorageBackend
base::File* file,
const std::vector<std::unique_ptr<sessions::SessionCommand>>& commands);
// Writes |command| to |file|. Returns true on success.
bool AppendCommandToFile(base::File* file,
const sessions::SessionCommand& command);
// Encrypts |command| and writes it to |file|. Returns true on success.
// The contents of the command and id are encrypted together. This is
// preceded by the length of the command.
bool AppendEncryptedCommandToFile(base::File* file,
const sessions::SessionCommand& command);
// Returns true if commands are encrypted.
bool IsEncrypted() const { return !crypto_key_.empty(); }
// Path commands are saved to.
const base::FilePath path_;
......@@ -122,6 +145,12 @@ class SESSIONS_EXPORT CommandStorageBackend
// runner.
bool inited_ = false;
std::vector<uint8_t> crypto_key_;
std::unique_ptr<crypto::Aead> aead_;
// Incremented every time a command is written.
int commands_written_ = 0;
DISALLOW_COPY_AND_ASSIGN(CommandStorageBackend);
};
......
This diff is collapsed.
......@@ -15,6 +15,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/sessions/core/command_storage_backend.h"
#include "components/sessions/core/command_storage_manager_delegate.h"
#include "crypto/random.h"
namespace sessions {
namespace {
......@@ -50,14 +51,24 @@ constexpr base::TimeDelta kSaveDelay = base::TimeDelta::FromMilliseconds(2500);
CommandStorageManager::CommandStorageManager(
const base::FilePath& path,
CommandStorageManagerDelegate* delegate)
CommandStorageManagerDelegate* delegate,
bool enable_crypto)
: CommandStorageManager(base::MakeRefCounted<CommandStorageBackend>(
CreateDefaultBackendTaskRunner(),
path),
delegate) {}
delegate) {
use_crypto_ = enable_crypto;
}
CommandStorageManager::~CommandStorageManager() = default;
// static
std::vector<uint8_t> CommandStorageManager::CreateCryptoKey() {
std::vector<uint8_t> key(32);
crypto::RandBytes(&(key.front()), key.size());
return key;
}
void CommandStorageManager::ScheduleCommand(
std::unique_ptr<SessionCommand> command) {
DCHECK(command);
......@@ -118,12 +129,15 @@ void CommandStorageManager::Save() {
if (pending_commands_.empty())
return;
// We create a new vector which will receive all elements from the
// current commands. This will also clear the current list.
std::vector<uint8_t> crypto_key;
if (use_crypto_ && pending_reset_) {
crypto_key = CreateCryptoKey();
delegate_->OnGeneratedNewCryptoKey(crypto_key);
}
backend_task_runner()->PostNonNestableTask(
FROM_HERE,
base::BindOnce(&CommandStorageBackend::AppendCommands, backend_,
std::move(pending_commands_), pending_reset_));
std::move(pending_commands_), pending_reset_, crypto_key));
if (pending_reset_) {
commands_since_reset_ = 0;
......@@ -138,6 +152,7 @@ bool CommandStorageManager::HasPendingSave() const {
base::CancelableTaskTracker::TaskId
CommandStorageManager::ScheduleGetCurrentSessionCommands(
GetCommandsCallback callback,
const std::vector<uint8_t>& decryption_key,
base::CancelableTaskTracker* tracker) {
base::CancelableTaskTracker::IsCanceledCallback is_canceled;
GetCommandsCallback backend_callback;
......@@ -147,7 +162,8 @@ CommandStorageManager::ScheduleGetCurrentSessionCommands(
backend_task_runner()->PostNonNestableTask(
FROM_HERE,
base::BindOnce(&CommandStorageBackend::ReadCurrentSessionCommands,
backend_.get(), is_canceled, std::move(backend_callback)));
backend_.get(), is_canceled, decryption_key,
std::move(backend_callback)));
return id;
}
......
......@@ -5,7 +5,10 @@
#ifndef COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_MANAGER_H_
#define COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_MANAGER_H_
#include <stddef.h>
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
......@@ -37,12 +40,16 @@ class SESSIONS_EXPORT CommandStorageManager {
// Creates a new CommandStorageManager. After creation you need to invoke
// Init. |delegate| will remain owned by the creator and it is guaranteed
// that its lifetime surpasses this class.
// |type| gives the type of session service, |path| the path to save files to.
// that its lifetime surpasses this class. |path| is the path to save files
// to. If |enable_crypto| is true, the contents of the file are encrypted.
CommandStorageManager(const base::FilePath& path,
CommandStorageManagerDelegate* delegate);
CommandStorageManagerDelegate* delegate,
bool enable_crypto = false);
virtual ~CommandStorageManager();
// Helper to generate a new key.
static std::vector<uint8_t> CreateCryptoKey();
// Returns the set of commands which were scheduled to be written. Once
// committed to the backend, the commands are removed from here.
const std::vector<std::unique_ptr<SessionCommand>>& pending_commands() {
......@@ -88,9 +95,11 @@ class SESSIONS_EXPORT CommandStorageManager {
// occurred.
bool HasPendingSave() const;
// Requests the commands for the current session.
// Requests the commands for the current session. If |decryption_key| is
// non-empty it is used to decrypt the contents of the file.
base::CancelableTaskTracker::TaskId ScheduleGetCurrentSessionCommands(
GetCommandsCallback callback,
const std::vector<uint8_t>& decryption_key,
base::CancelableTaskTracker* tracker);
protected:
......@@ -122,6 +131,9 @@ class SESSIONS_EXPORT CommandStorageManager {
// The backend object which reads and saves commands.
scoped_refptr<CommandStorageBackend> backend_;
// If true, all commands are encrypted.
bool use_crypto_ = false;
// Commands we need to send over to the backend.
std::vector<std::unique_ptr<SessionCommand>> pending_commands_;
......
......@@ -5,6 +5,10 @@
#ifndef COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_MANAGER_DELEGATE_H_
#define COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_MANAGER_DELEGATE_H_
#include <stddef.h>
#include <vector>
namespace sessions {
// The CommandStorageManagerDelegate decouples the CommandStorageManager from
......@@ -20,6 +24,10 @@ class CommandStorageManagerDelegate {
// Called when commands are about to be written to disc.
virtual void OnWillSaveCommands() {}
// Called when a new crypto key has been generated. This is only called if
// CommandStorageManager was configured to enable encryption.
virtual void OnGeneratedNewCryptoKey(const std::vector<uint8_t>& key) {}
protected:
virtual ~CommandStorageManagerDelegate() {}
};
......
......@@ -62,7 +62,7 @@ void SnapshottingCommandStorageBackend::ReadLastSessionCommands(
InitIfNecessary();
std::vector<std::unique_ptr<sessions::SessionCommand>> commands;
ReadCommandsFromFile(last_file_path_, &commands);
ReadCommandsFromFile(last_file_path_, std::vector<uint8_t>(), &commands);
std::move(callback).Run(std::move(commands));
}
......
......@@ -69,7 +69,7 @@ SessionService::SessionService(const base::FilePath& path, BrowserImpl* browser)
command_storage_manager_->ScheduleGetCurrentSessionCommands(
base::BindOnce(&SessionService::OnGotCurrentSessionCommands,
base::Unretained(this)),
&cancelable_task_tracker_);
std::vector<uint8_t>(), &cancelable_task_tracker_);
}
SessionService::~SessionService() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment