Files

165 lines
6.0 KiB
C++

/* Copyright 2019 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "brave/components/brave_sync/crypto/crypto.h"
#include <cmath>
#include "base/check.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "brave/third_party/bip39wally-core-native/include/wally_bip39.h"
#include "brave/vendor/bat-native-tweetnacl/tweetnacl.h"
#include "crypto/random.h"
#include "third_party/boringssl/src/include/openssl/curve25519.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/hkdf.h"
namespace brave_sync::crypto {
std::vector<uint8_t> GetSeed(size_t size) {
if (size < DEFAULT_SEED_SIZE) {
size = DEFAULT_SEED_SIZE;
}
std::vector<uint8_t> bytes(size);
::crypto::RandBytes(bytes);
return bytes;
}
std::vector<uint8_t> HKDFSha512(const std::vector<uint8_t>& ikm,
const std::vector<uint8_t>* salt,
const std::vector<uint8_t>* info,
size_t derived_key_size) {
std::vector<uint8_t> derived_key(derived_key_size);
int result =
HKDF(derived_key.data(), derived_key.size(), EVP_sha512(), ikm.data(),
ikm.size(), salt ? salt->data() : nullptr, salt ? salt->size() : 0,
info ? info->data() : nullptr, info ? info->size() : 0);
CHECK(result);
return derived_key;
}
void DeriveSigningKeysFromSeed(const std::vector<uint8_t>& seed,
const std::vector<uint8_t>* salt,
const std::vector<uint8_t>* info,
std::vector<uint8_t>* public_key,
std::vector<uint8_t>* private_key) {
DCHECK(public_key);
DCHECK(private_key);
DCHECK(info);
std::vector<uint8_t> output =
HKDFSha512(seed, salt, info, DEFAULT_SEED_SIZE);
public_key->resize(ED25519_PUBLIC_KEY_LEN);
private_key->resize(ED25519_PRIVATE_KEY_LEN);
ED25519_keypair_from_seed(public_key->data(), private_key->data(),
output.data());
}
bool Sign(const std::vector<uint8_t>& message,
const std::vector<uint8_t>& private_key,
std::vector<uint8_t>* out_sig) {
DCHECK(out_sig);
DCHECK_EQ(private_key.size(), (size_t)ED25519_PRIVATE_KEY_LEN);
out_sig->resize(ED25519_SIGNATURE_LEN);
return ED25519_sign(out_sig->data(), message.data(), message.size(),
private_key.data());
}
bool Verify(const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature,
const std::vector<uint8_t>& public_key) {
DCHECK_EQ(signature.size(), (size_t)ED25519_SIGNATURE_LEN);
DCHECK_EQ(public_key.size(), (size_t)ED25519_PUBLIC_KEY_LEN);
return ED25519_verify(message.data(), message.size(), signature.data(),
public_key.data());
}
std::vector<uint8_t> GetNonce(uint16_t counter,
const std::vector<uint8_t>& nonce_bytes) {
DCHECK_EQ(nonce_bytes.size(), (size_t)20);
std::vector<uint8_t> nonce(crypto_secretbox_NONCEBYTES);
nonce[0] = std::floor(counter / 256);
nonce[1] = counter % 256;
for (size_t i = 0; i < nonce_bytes.size(); ++i) {
nonce[i + 2] = nonce_bytes[i];
}
return nonce;
}
bool Encrypt(const std::vector<uint8_t>& message,
const std::vector<uint8_t>& nonce,
const std::vector<uint8_t>& secretbox_key,
std::vector<uint8_t>* ciphertext) {
DCHECK(ciphertext);
DCHECK_EQ(secretbox_key.size(), (size_t)crypto_secretbox_KEYBYTES);
DCHECK_EQ(nonce.size(), (size_t)crypto_secretbox_NONCEBYTES);
std::vector<uint8_t> m(crypto_secretbox_ZEROBYTES + message.size());
std::vector<uint8_t> c(m.size());
for (size_t i = 0; i < message.size(); ++i) {
m[i + crypto_secretbox_ZEROBYTES] = message[i];
}
if (crypto_secretbox(c.data(), m.data(), m.size(), nonce.data(),
secretbox_key.data()) != 0)
return false;
*ciphertext =
std::vector<uint8_t>(c.begin() + crypto_secretbox_BOXZEROBYTES, c.end());
return true;
}
bool Decrypt(const std::vector<uint8_t>& ciphertext,
const std::vector<uint8_t>& nonce,
const std::vector<uint8_t>& secretbox_key,
std::vector<uint8_t>* message) {
DCHECK(message);
DCHECK_EQ(secretbox_key.size(), (size_t)crypto_secretbox_KEYBYTES);
DCHECK_EQ(nonce.size(), (size_t)crypto_secretbox_NONCEBYTES);
std::vector<uint8_t> c(crypto_secretbox_BOXZEROBYTES + ciphertext.size());
if (c.size() < 32)
return false;
std::vector<uint8_t> m(c.size());
for (size_t i = 0; i < ciphertext.size(); ++i) {
c[i + crypto_secretbox_BOXZEROBYTES] = ciphertext[i];
}
if (crypto_secretbox_open(m.data(), c.data(), c.size(), nonce.data(),
secretbox_key.data()) != 0)
return false;
*message =
std::vector<uint8_t>(m.begin() + crypto_secretbox_ZEROBYTES, m.end());
return true;
}
std::string PassphraseFromBytes32(const std::vector<uint8_t>& bytes) {
DCHECK_EQ(bytes.size(), (size_t)DEFAULT_SEED_SIZE);
char* words = nullptr;
std::string passphrase;
CHECK_EQ(
bip39_mnemonic_from_bytes(nullptr, bytes.data(), bytes.size(), &words),
WALLY_OK);
passphrase = words;
wally_free_string(words);
return passphrase;
}
bool PassphraseToBytes32(const std::string& passphrase,
std::vector<uint8_t>* bytes) {
DCHECK(bytes);
size_t written;
bytes->resize(DEFAULT_SEED_SIZE);
if (bip39_mnemonic_to_bytes(nullptr, passphrase.c_str(), bytes->data(),
bytes->size(), &written) != WALLY_OK) {
LOG(ERROR) << "bip39_mnemonic_to_bytes failed";
return false;
}
return true;
}
bool IsPassphraseValid(const std::string& passphrase) {
std::vector<uint8_t> bytes;
return PassphraseToBytes32(passphrase, &bytes);
}
} // namespace brave_sync::crypto