blob: 430756986205ac4edf42f1352cebefd1d450fe35 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/enterprise/connectors/device_trust/attestation/desktop/crypto_utility.h"
#include "base/containers/span.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "crypto/encryptor.h"
#include "crypto/random.h"
#include "crypto/signature_verifier.h"
#include "crypto/symmetric_key.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/hmac.h"
#include "third_party/boringssl/src/include/openssl/mem.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
namespace enterprise_connectors {
namespace CryptoUtility {
namespace {
const unsigned int kWellKnownExponent = 65537;
const size_t kAesKeySizeBits = 256;
const size_t kAesBlockSize = 16;
const unsigned char* StringAsConstOpenSSLBuffer(const std::string& s) {
return reinterpret_cast<const unsigned char*>(s.data());
}
unsigned char* StringAsOpenSSLBuffer(std::string* s) {
return reinterpret_cast<unsigned char*>(std::data(*s));
}
} // namespace
bssl::UniquePtr<RSA> GetRSA(const std::string& public_key_modulus_hex) {
bssl::UniquePtr<RSA> rsa(RSA_new());
bssl::UniquePtr<BIGNUM> n(BN_new());
bssl::UniquePtr<BIGNUM> e(BN_new());
if (!rsa || !e || !n) {
LOG(ERROR) << __func__ << ": Failed to allocate RSA or BIGNUMs.";
return nullptr;
}
BIGNUM* pn = n.get();
if (!BN_set_word(e.get(), kWellKnownExponent) ||
!BN_hex2bn(&pn, public_key_modulus_hex.c_str())) {
LOG(ERROR) << __func__ << ": Failed to generate exponent or modulus.";
return nullptr;
}
if (!RSA_set0_key(rsa.get(), n.release(), e.release(), nullptr)) {
LOG(ERROR) << __func__ << ": Failed to set exponent or modulus.";
return nullptr;
}
return rsa;
}
bool CreatePubKeyFromHex(const std::string& public_key_modulus_hex,
std::vector<uint8_t>& public_key_info) {
bssl::UniquePtr<RSA> rsa = GetRSA(public_key_modulus_hex);
bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
EVP_PKEY_assign_RSA(public_key.get(), rsa.release());
uint8_t* der;
size_t der_len;
bssl::ScopedCBB cbb;
if (!CBB_init(cbb.get(), 0) ||
!EVP_marshal_public_key(cbb.get(), public_key.get()) ||
!CBB_finish(cbb.get(), &der, &der_len)) {
return false;
}
public_key_info.assign(der, der + der_len);
OPENSSL_free(der);
return true;
}
bool VerifySignatureUsingHexKey(const std::string& public_key_modulus_hex,
const std::string& data,
const std::string& signature) {
std::vector<uint8_t> public_key_info;
if (!CreatePubKeyFromHex(public_key_modulus_hex, public_key_info)) {
return false;
}
crypto::SignatureVerifier verifier;
if (!verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA256,
base::as_bytes(base::make_span(signature)),
base::as_bytes(base::make_span(public_key_info))))
return false;
verifier.VerifyUpdate(base::as_bytes(base::make_span(data)));
return verifier.VerifyFinal();
}
std::string HmacSha512(const std::string& key, const std::string& data) {
unsigned char mac[SHA512_DIGEST_LENGTH];
std::string mutable_data(data);
unsigned char* data_buffer = StringAsOpenSSLBuffer(&mutable_data);
HMAC(EVP_sha512(), key.data(), key.size(), data_buffer, data.size(), mac,
nullptr);
return std::string(std::begin(mac), std::end(mac));
}
bool EncryptWithSeed(const std::string& data,
EncryptedData* encrypted,
std::string& key) {
// Generate AES key of size 256 bits.
std::unique_ptr<crypto::SymmetricKey> symmetric_key(
crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES,
kAesKeySizeBits));
if (!symmetric_key)
return false;
key = symmetric_key->key();
// Generate initialized vector of size 128 bits.
std::string iv;
crypto::RandBytes(base::WriteInto(&iv, kAesBlockSize + 1), kAesBlockSize);
crypto::Encryptor encryptor;
if (!encryptor.Init(symmetric_key.get(), crypto::Encryptor::CBC, iv))
return false;
if (!encryptor.Encrypt(data, encrypted->mutable_encrypted_data()))
return false;
encrypted->set_iv(iv);
encrypted->set_mac(HmacSha512(key, iv + encrypted->encrypted_data()));
return true;
}
bool WrapKeyOAEP(const std::string& key,
RSA* wrapping_key,
const std::string& wrapping_key_id,
EncryptedData* output) {
const unsigned char* key_buffer = StringAsConstOpenSSLBuffer(key);
std::string encrypted_key;
if (!wrapping_key) {
LOG(ERROR) << "No wrapping_key.";
return false;
}
encrypted_key.resize(RSA_size(wrapping_key));
unsigned char* encrypted_key_buffer = StringAsOpenSSLBuffer(&encrypted_key);
int length = RSA_public_encrypt(key.size(), key_buffer, encrypted_key_buffer,
wrapping_key, RSA_PKCS1_OAEP_PADDING);
if (length == -1) {
LOG(ERROR) << "RSA_public_encrypt failed.";
return false;
}
encrypted_key.resize(length);
output->set_wrapped_key(encrypted_key);
output->set_wrapping_key_id(wrapping_key_id);
return true;
}
} // namespace CryptoUtility
} // namespace enterprise_connectors