Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend Work for Crypto Wallets reset feature #4364

Merged
merged 2 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ source_set("browser_process") {
"//brave/components/brave_referrals/browser",
"//brave/components/brave_rewards/browser",
"//brave/components/brave_shields/browser",
"//brave/components/brave_wallet/browser",
"//brave/components/brave_wayback_machine:buildflags",
"//brave/components/brave_webtorrent/browser/buildflags",
"//brave/components/content_settings/core/browser",
Expand Down Expand Up @@ -172,6 +171,12 @@ source_set("browser_process") {
"//ui/base",
]

if (brave_wallet_enabled) {
deps += [
"//brave/components/brave_wallet/browser",
]
}

if (enable_greaselion) {
deps += [
"greaselion",
Expand Down
168 changes: 32 additions & 136 deletions browser/extensions/api/brave_wallet_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <memory>
#include <string>

#include "base/base64.h"
#include "base/environment.h"
#include "brave/browser/infobars/crypto_wallets_infobar_delegate.h"
#include "brave/browser/profiles/profile_util.h"
Expand All @@ -21,19 +20,26 @@
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_contents.h"
#include "crypto/aead.h"
#include "crypto/hkdf.h"
#include "crypto/random.h"
#include "crypto/symmetric_key.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
#include "brave/components/brave_wallet/browser/brave_wallet_service_factory.h"
#include "brave/components/brave_wallet/browser/brave_wallet_controller.h"
#include "brave/components/brave_wallet/browser/brave_wallet_service.h"

namespace {

BraveWalletController* GetBraveWalletController(
content::BrowserContext* context) {
return BraveWalletServiceFactory::GetInstance()
->GetForProfile(Profile::FromBrowserContext(context))
->controller();
}

} // namespace

namespace extensions {
namespace api {

const size_t BraveWalletGetWalletSeedFunction::kNonceByteLength = 12;
const size_t BraveWalletGetWalletSeedFunction::kSeedByteLength = 32;

ExtensionFunction::ResponseAction
BraveWalletPromptToEnableWalletFunction::Run() {
std::unique_ptr<brave_wallet::PromptToEnableWallet::Params> params(
Expand Down Expand Up @@ -88,105 +94,6 @@ BraveWalletIsEnabledFunction::Run() {
return RespondNow(OneArgument(std::make_unique<base::Value>(enabled)));
}

// Returns 32 bytes of output from HKDF-SHA256.
// This is done so that ethereum-remote-client never actually directly has
// access to the master seed, but it does have a deterministic seed.
// The salt value is the same intentionally on all clients.
// See https://github.com/brave/brave-browser/wiki/Brave-Ethereum-Remote-Client-Wallet-Seed-Information#note-on-salts
std::string
BraveWalletGetWalletSeedFunction::GetEthereumRemoteClientSeedFromRootSeed(
const std::string& seed) {
base::StringPiece salt("brave-ethwallet-salt");
base::StringPiece info("ethwallet");
return crypto::HkdfSha256(base::StringPiece(seed.begin(), seed.end()),
salt, info, kSeedByteLength);
}

bool
BraveWalletGetWalletSeedFunction::SealSeed(const std::string& seed,
const std::string& key, const std::string& nonce,
std::string* cipher_seed) {
crypto::Aead aes_256_gcm_siv(crypto::Aead::AES_256_GCM_SIV);
aes_256_gcm_siv.Init(&key);
return aes_256_gcm_siv.Seal(base::StringPiece(seed.begin(), seed.end()),
nonce, base::StringPiece(""), cipher_seed);
}

bool BraveWalletGetWalletSeedFunction::OpenSeed(const std::string& cipher_seed,
const std::string& key, const std::string& nonce,
std::string* seed) {
crypto::Aead aes_256_gcm_siv(crypto::Aead::AES_256_GCM_SIV);
aes_256_gcm_siv.Init(&key);
return aes_256_gcm_siv.Open(cipher_seed, nonce, base::StringPiece(""), seed);
}

// Store the seed in preferences, binary pref strings need to be
// base64 encoded. Base64 encoding is fail safe.
void BraveWalletGetWalletSeedFunction::SaveToPrefs(
Profile* profile, const std::string& cipher_seed,
const std::string& nonce) {
// Store the seed in preferences, binary pref strings need to be
// base64 encoded. Base64 encoding is fail safe.
std::string base64_nonce;
std::string base64_cipher_seed;
base::Base64Encode(nonce, &base64_nonce);
base::Base64Encode(base::StringPiece(cipher_seed.begin(),
cipher_seed.end()),
&base64_cipher_seed);
profile->GetPrefs()->SetString(kBraveWalletAES256GCMSivNonce, base64_nonce);
profile->GetPrefs()->SetString(kBraveWalletEncryptedSeed,
base64_cipher_seed);
}

bool BraveWalletGetWalletSeedFunction::LoadFromPrefs(
Profile* profile, std::string* cipher_seed, std::string* nonce) {
if (!profile->GetPrefs()->HasPrefPath(kBraveWalletAES256GCMSivNonce) ||
!profile->GetPrefs()->HasPrefPath(kBraveWalletEncryptedSeed)) {
return false;
}
if (!base::Base64Decode(
profile->GetPrefs()->GetString(kBraveWalletAES256GCMSivNonce),
nonce)) {
return false;
}
if (!base::Base64Decode(
profile->GetPrefs()->GetString(kBraveWalletEncryptedSeed),
cipher_seed)) {
return false;
}
return true;
}

// Generate a new random nonce
std::string BraveWalletGetWalletSeedFunction::GetRandomNonce() {
// crypto::RandBytes is fail safe.
uint8_t nonceBytes[kNonceByteLength];
crypto::RandBytes(nonceBytes, kNonceByteLength);
return std::string(
reinterpret_cast<char*>(nonceBytes), kNonceByteLength);
}

// Generate a new seed.
std::string BraveWalletGetWalletSeedFunction::GetRandomSeed() {
// crypto::RandBytes is fail safe.
uint8_t random_seed_bytes[kSeedByteLength];
crypto::RandBytes(random_seed_bytes, kSeedByteLength);
return std::string(
reinterpret_cast<char*>(random_seed_bytes), kSeedByteLength);
}

// Generates a random 32 byte root seed and stores it in prefs
// in an encrypted form. It also stores the nonce that was used
// from AES 256 GCM SIV.
// If this function is called multiple times, the previous value
// from prefs will be re-used.
// The return value is passed to chrome.braveWallet.getWalletSeed
// via the second paramter callback function.
// The return value will not be the root seed, but instead a
// deterministic hash of that seed with HKDF, so that we can use
// other HKDF hashes with different info parameters for different purposes.
// For more information, see:
// https://github.com/brave/brave-browser/wiki/Brave-Ethereum-Remote-Client-Wallet-Seed-Information
ExtensionFunction::ResponseAction
BraveWalletGetWalletSeedFunction::Run() {
// make sure the passed in enryption key is 32 bytes.
Expand All @@ -196,38 +103,20 @@ BraveWalletGetWalletSeedFunction::Run() {
return RespondNow(Error("Invalid input key size"));
}

std::string nonce;
std::string cipher_seed;
std::string seed;
// Check if we already have a nonce and seed stored in prefs.
std::string aes_256_gcm_siv_key(params->key.begin(), params->key.end());
if (LoadFromPrefs(Profile::FromBrowserContext(browser_context()),
&cipher_seed, &nonce)) {
// Decrypt the existing seed.
if (!OpenSeed(cipher_seed, aes_256_gcm_siv_key, nonce, &seed)) {
return RespondNow(Error("Error decrypting cipher seed"));
}
} else {
// No valid previous value was stored, so generate new random values.
nonce = GetRandomNonce();
seed = GetRandomSeed();
// Encrypt that seed.
if (!SealSeed(seed, aes_256_gcm_siv_key, nonce, &cipher_seed)) {
return RespondNow(Error("Error encrypting"));
}
// Save it to prefs.
SaveToPrefs(Profile::FromBrowserContext(browser_context()), cipher_seed,
nonce);
}
// We should have the correct nonce size and seed size at this point
// regardless of if it was newly genearted or retrieved from prefs.
DCHECK_EQ(nonce.size(), kNonceByteLength);
DCHECK_EQ(seed.size(), kSeedByteLength);
std::string derived = GetEthereumRemoteClientSeedFromRootSeed(seed);
auto* controller = GetBraveWalletController(browser_context());

base::Value::BlobStorage blob;
std::string derived = controller->GetWalletSeed(
params->key);

if (derived.empty()) {
return RespondNow(Error("Error getting wallet seed"));
}

blob.assign(derived.begin(), derived.end());

return RespondNow(OneArgument(
std::make_unique<base::Value>(blob)));
std::make_unique<base::Value>(blob)));
}

ExtensionFunction::ResponseAction
Expand All @@ -241,5 +130,12 @@ BraveWalletGetProjectIDFunction::Run() {
std::make_unique<base::Value>(project_id)));
}

ExtensionFunction::ResponseAction
BraveWalletResetWalletFunction::Run() {
auto* controller = GetBraveWalletController(browser_context());
controller->ResetCryptoWallets();
return RespondNow(NoArguments());
}

} // namespace api
} // namespace extensions
25 changes: 10 additions & 15 deletions browser/extensions/api/brave_wallet_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,6 @@ class BraveWalletGetWalletSeedFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("braveWallet.getWalletSeed", UNKNOWN)

static std::string GetEthereumRemoteClientSeedFromRootSeed(
const std::string& seed);
static bool SealSeed(const std::string& seed, const std::string& key,
const std::string& nonce, std::string* cipher_seed);
static bool OpenSeed(const std::string& cipher_seed,
const std::string& key, const std::string& nonce, std::string* seed);
static void SaveToPrefs(Profile *, const std::string& cipher_seed,
const std::string& nonce);
static bool LoadFromPrefs(Profile *, std::string* cipher_seed,
std::string* nonce);
static std::string GetRandomNonce();
static std::string GetRandomSeed();
static const size_t kNonceByteLength;
static const size_t kSeedByteLength;

protected:
~BraveWalletGetWalletSeedFunction() override {}

Expand All @@ -81,6 +66,16 @@ class BraveWalletGetProjectIDFunction : public ExtensionFunction {
ResponseAction Run() override;
};

class BraveWalletResetWalletFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("braveWallet.resetWallet", UNKNOWN)

protected:
~BraveWalletResetWalletFunction() override {}

ResponseAction Run() override;
};

} // namespace api
} // namespace extensions

Expand Down
22 changes: 10 additions & 12 deletions browser/extensions/brave_wallet_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "brave/browser/extensions/api/brave_wallet_api.h"
#include "brave/components/brave_wallet/browser/brave_wallet_controller.h"

#include "brave/common/pref_names.h"
#include "chrome/browser/profiles/profile_manager.h"
Expand All @@ -14,8 +14,6 @@
#include "extensions/buildflags/buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"

using extensions::api::BraveWalletGetWalletSeedFunction;

class BraveWalletUnitTest : public testing::Test {
public:
BraveWalletUnitTest()
Expand All @@ -39,13 +37,13 @@ class BraveWalletUnitTest : public testing::Test {
};

TEST_F(BraveWalletUnitTest, TestGetRandomNonce) {
std::string nonce = BraveWalletGetWalletSeedFunction::GetRandomNonce();
ASSERT_EQ(nonce.size(), BraveWalletGetWalletSeedFunction::kNonceByteLength);
std::string nonce = BraveWalletController::GetRandomNonce();
ASSERT_EQ(nonce.size(), BraveWalletController::kNonceByteLength);
}

TEST_F(BraveWalletUnitTest, TestGetRandomSeed) {
std::string seed = BraveWalletGetWalletSeedFunction::GetRandomSeed();
ASSERT_EQ(seed.size(), BraveWalletGetWalletSeedFunction::kSeedByteLength);
std::string seed = BraveWalletController::GetRandomSeed();
ASSERT_EQ(seed.size(), BraveWalletController::kSeedByteLength);
}

TEST_F(BraveWalletUnitTest, TestGetEthereumRemoteClientSeedFromRootSeed) {
Expand All @@ -62,7 +60,7 @@ TEST_F(BraveWalletUnitTest, TestGetEthereumRemoteClientSeedFromRootSeed) {
52, 76, 223, 24, 183, 138, 244, 72
};
std::string derived =
BraveWalletGetWalletSeedFunction::GetEthereumRemoteClientSeedFromRootSeed(
BraveWalletController::GetEthereumRemoteClientSeedFromRootSeed(
std::string(seed, base::size(seed)));
ASSERT_EQ(derived, std::string(expected_derived_seed,
base::size(expected_derived_seed)));
Expand Down Expand Up @@ -93,7 +91,7 @@ TEST_F(BraveWalletUnitTest, TestSealSeed) {
222, 231, 48, 93, 132, 131, 178, 177
};
std::string cipher_seed;
ASSERT_TRUE(BraveWalletGetWalletSeedFunction::SealSeed(
ASSERT_TRUE(BraveWalletController::SealSeed(
std::string(seed, base::size(seed)), std::string(key, base::size(key)),
std::string(nonce, base::size(nonce)), &cipher_seed));
ASSERT_EQ(cipher_seed, std::string(expected_cipher_seed,
Expand Down Expand Up @@ -125,7 +123,7 @@ TEST_F(BraveWalletUnitTest, TestOpenSeed) {
232, 187, 188, 220, 160, 187, 212, 28
};
std::string seed;
ASSERT_TRUE(BraveWalletGetWalletSeedFunction::OpenSeed(
ASSERT_TRUE(BraveWalletController::OpenSeed(
std::string(cipher_seed, base::size(cipher_seed)),
std::string(key, base::size(key)),
std::string(nonce, base::size(nonce)), &seed));
Expand All @@ -139,7 +137,7 @@ TEST_F(BraveWalletUnitTest, TestLoadFromPrefs) {

std::string cipher_seed;
std::string nonce;
ASSERT_TRUE(BraveWalletGetWalletSeedFunction::LoadFromPrefs(
ASSERT_TRUE(BraveWalletController::LoadFromPrefs(
ProfileManager::GetActiveUserProfile(), &cipher_seed, &nonce));

const char expected_nonce[12] = {
Expand Down Expand Up @@ -170,7 +168,7 @@ TEST_F(BraveWalletUnitTest, TestSaveToPrefs) {
6, 128, 179, 64, 55, 160, 219, 8,
222, 231, 48, 93, 132, 131, 178, 177
};
BraveWalletGetWalletSeedFunction::SaveToPrefs(
BraveWalletController::SaveToPrefs(
ProfileManager::GetActiveUserProfile(),
std::string(cipher_seed, base::size(cipher_seed)),
std::string(nonce, base::size(nonce)));
Expand Down
5 changes: 5 additions & 0 deletions common/extensions/api/brave_wallet.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
]
}
]
}, {
"name": "resetWallet",
"type": "function",
"description": "Called to restore Crypto Wallets to its original state",
"parameters": []
}
],
"types": [
Expand Down
16 changes: 16 additions & 0 deletions components/brave_wallet/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,20 @@ source_set("browser") {
public_deps = [
"buildflags"
]

sources = [
"brave_wallet_service.h",
"brave_wallet_service.cc",
"brave_wallet_controller.h",
"brave_wallet_controller.cc",
"brave_wallet_service_factory.h",
"brave_wallet_service_factory.cc",
]

deps = [
"//base",
"//components/keyed_service/content",
"//components/keyed_service/core",
"//content/public/browser",
]
}
Loading