blob: 4f9305ea9b4ffad0c9be01d934d79ad6f48263f4 [file] [log] [blame]
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crypto/symmetric_key.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <utility>
#include "base/check_op.h"
#include "base/notreached.h"
#include "crypto/kdf.h"
#include "crypto/openssl_util.h"
#include "crypto/random.h"
namespace crypto {
namespace {
bool IsValidKeySize(size_t key_size_in_bytes) {
// Nobody should ever be using other symmetric key sizes without consulting
// with CRYPTO_OWNERS first, who can modify this check if need be.
return key_size_in_bytes == 16 || key_size_in_bytes == 32;
}
} // namespace
SymmetricKey::SymmetricKey(base::span<const uint8_t> key_bytes)
: key_(base::as_string_view(key_bytes)) {}
SymmetricKey::SymmetricKey(const SymmetricKey& other) = default;
SymmetricKey& SymmetricKey::operator=(const SymmetricKey& other) = default;
SymmetricKey::~SymmetricKey() {
std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key.
}
// static
std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey(
Algorithm,
size_t key_size_in_bits) {
return std::make_unique<SymmetricKey>(RandomKey(key_size_in_bits));
}
// static
SymmetricKey SymmetricKey::RandomKey(size_t key_size_in_bits) {
CHECK(!(key_size_in_bits % 8));
const size_t key_size_in_bytes = key_size_in_bits / 8;
CHECK(IsValidKeySize(key_size_in_bytes));
return SymmetricKey(crypto::RandBytesAsVector(key_size_in_bytes));
}
// static
std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
Algorithm,
const std::string& password,
const std::string& salt,
size_t iterations,
size_t key_size_in_bits) {
if ((key_size_in_bits % 8) || !IsValidKeySize(key_size_in_bits / 8)) {
return nullptr;
}
kdf::Pbkdf2HmacSha1Params params = {
.iterations = base::checked_cast<decltype(params.iterations)>(iterations),
};
std::vector<uint8_t> key(key_size_in_bits / 8);
kdf::DeriveKeyPbkdf2HmacSha1(params, base::as_byte_span(password),
base::as_byte_span(salt), key, SubtlePassKey{});
return std::make_unique<SymmetricKey>(key);
}
// static
std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingScrypt(
Algorithm,
const std::string& password,
const std::string& salt,
size_t cost_parameter,
size_t block_size,
size_t parallelization_parameter,
size_t max_memory_bytes,
size_t key_size_in_bits) {
if ((key_size_in_bits % 8) || !IsValidKeySize(key_size_in_bits / 8)) {
return nullptr;
}
kdf::ScryptParams params = {
.cost = cost_parameter,
.block_size = block_size,
.parallelization = parallelization_parameter,
.max_memory_bytes = max_memory_bytes,
};
std::vector<uint8_t> key(key_size_in_bits / 8);
kdf::DeriveKeyScrypt(params, base::as_byte_span(password),
base::as_byte_span(salt), key, SubtlePassKey{});
return std::make_unique<SymmetricKey>(key);
}
// static
std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm,
const std::string& raw_key) {
if (!IsValidKeySize(raw_key.size())) {
return nullptr;
}
return std::make_unique<SymmetricKey>(base::as_byte_span(raw_key));
}
} // namespace crypto