1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crypto/symmetric_key.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <algorithm>
11 #include <utility>
12
13 #include "base/check_op.h"
14 #include "base/notreached.h"
15 #include "crypto/kdf.h"
16 #include "crypto/openssl_util.h"
17 #include "crypto/random.h"
18
19 namespace crypto {
20
21 namespace {
22
IsValidKeySize(size_t key_size_in_bytes)23 bool IsValidKeySize(size_t key_size_in_bytes) {
24 // Nobody should ever be using other symmetric key sizes without consulting
25 // with CRYPTO_OWNERS first, who can modify this check if need be.
26 return key_size_in_bytes == 16 || key_size_in_bytes == 32;
27 }
28
29 } // namespace
30
SymmetricKey(base::span<const uint8_t> key_bytes)31 SymmetricKey::SymmetricKey(base::span<const uint8_t> key_bytes)
32 : key_(base::as_string_view(key_bytes)) {}
33
34 SymmetricKey::SymmetricKey(const SymmetricKey& other) = default;
35 SymmetricKey& SymmetricKey::operator=(const SymmetricKey& other) = default;
36
~SymmetricKey()37 SymmetricKey::~SymmetricKey() {
38 std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key.
39 }
40
41 // static
GenerateRandomKey(Algorithm,size_t key_size_in_bits)42 std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey(
43 Algorithm,
44 size_t key_size_in_bits) {
45 return std::make_unique<SymmetricKey>(RandomKey(key_size_in_bits));
46 }
47
48 // static
RandomKey(size_t key_size_in_bits)49 SymmetricKey SymmetricKey::RandomKey(size_t key_size_in_bits) {
50 CHECK(!(key_size_in_bits % 8));
51
52 const size_t key_size_in_bytes = key_size_in_bits / 8;
53 CHECK(IsValidKeySize(key_size_in_bytes));
54
55 return SymmetricKey(crypto::RandBytesAsVector(key_size_in_bytes));
56 }
57
58 // static
DeriveKeyFromPasswordUsingPbkdf2(Algorithm,const std::string & password,const std::string & salt,size_t iterations,size_t key_size_in_bits)59 std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
60 Algorithm,
61 const std::string& password,
62 const std::string& salt,
63 size_t iterations,
64 size_t key_size_in_bits) {
65 if ((key_size_in_bits % 8) || !IsValidKeySize(key_size_in_bits / 8)) {
66 return nullptr;
67 }
68
69 kdf::Pbkdf2HmacSha1Params params = {
70 .iterations = base::checked_cast<decltype(params.iterations)>(iterations),
71 };
72
73 std::vector<uint8_t> key(key_size_in_bits / 8);
74 kdf::DeriveKeyPbkdf2HmacSha1(params, base::as_byte_span(password),
75 base::as_byte_span(salt), key, SubtlePassKey{});
76
77 return std::make_unique<SymmetricKey>(key);
78 }
79
80 // static
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)81 std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingScrypt(
82 Algorithm,
83 const std::string& password,
84 const std::string& salt,
85 size_t cost_parameter,
86 size_t block_size,
87 size_t parallelization_parameter,
88 size_t max_memory_bytes,
89 size_t key_size_in_bits) {
90 if ((key_size_in_bits % 8) || !IsValidKeySize(key_size_in_bits / 8)) {
91 return nullptr;
92 }
93
94 kdf::ScryptParams params = {
95 .cost = cost_parameter,
96 .block_size = block_size,
97 .parallelization = parallelization_parameter,
98 .max_memory_bytes = max_memory_bytes,
99 };
100 std::vector<uint8_t> key(key_size_in_bits / 8);
101 kdf::DeriveKeyScrypt(params, base::as_byte_span(password),
102 base::as_byte_span(salt), key, SubtlePassKey{});
103 return std::make_unique<SymmetricKey>(key);
104 }
105
106 // static
Import(Algorithm,const std::string & raw_key)107 std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm,
108 const std::string& raw_key) {
109 if (!IsValidKeySize(raw_key.size())) {
110 return nullptr;
111 }
112 return std::make_unique<SymmetricKey>(base::as_byte_span(raw_key));
113 }
114
115 } // namespace crypto
116