Avi Drissman | 201a9a83 | 2022-09-13 19:39:25 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
rvargas@google.com | 4b559b4d | 2011-04-14 17:37:14 | [diff] [blame] | 5 | #include "crypto/symmetric_key.h" |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 6 | |
avi | dd373b8 | 2015-12-21 21:34:43 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 9 | |
| 10 | #include <algorithm> |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 11 | #include <utility> |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 12 | |
Hans Wennborg | 4d0e180 | 2020-04-24 20:19:43 | [diff] [blame] | 13 | #include "base/check_op.h" |
| 14 | #include "base/notreached.h" |
rvargas@google.com | 4b559b4d | 2011-04-14 17:37:14 | [diff] [blame] | 15 | #include "crypto/openssl_util.h" |
tfarina | 29a3a174 | 2016-10-28 18:47:33 | [diff] [blame] | 16 | #include "third_party/boringssl/src/include/openssl/evp.h" |
| 17 | #include "third_party/boringssl/src/include/openssl/rand.h" |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 18 | |
rvargas@google.com | 4b559b4d | 2011-04-14 17:37:14 | [diff] [blame] | 19 | namespace crypto { |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 20 | |
David Davidović | f8cd6a0 | 2018-08-27 14:02:51 | [diff] [blame] | 21 | namespace { |
| 22 | |
| 23 | bool CheckDerivationParameters(SymmetricKey::Algorithm algorithm, |
| 24 | size_t key_size_in_bits) { |
| 25 | switch (algorithm) { |
| 26 | case SymmetricKey::AES: |
David Benjamin | 9f832458 | 2022-03-01 23:40:55 | [diff] [blame] | 27 | // Check for supported key sizes. Historically, NSS supported AES-192 |
| 28 | // while BoringSSL did not and this check aligned their behavior. |
David Davidović | f8cd6a0 | 2018-08-27 14:02:51 | [diff] [blame] | 29 | return key_size_in_bits == 128 || key_size_in_bits == 256; |
| 30 | case SymmetricKey::HMAC_SHA1: |
| 31 | return key_size_in_bits % 8 == 0 && key_size_in_bits != 0; |
| 32 | } |
| 33 | |
| 34 | NOTREACHED(); |
| 35 | return false; |
| 36 | } |
| 37 | |
| 38 | } // namespace |
| 39 | |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 40 | SymmetricKey::~SymmetricKey() { |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 41 | std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key. |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | // static |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 45 | std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey( |
| 46 | Algorithm algorithm, |
| 47 | size_t key_size_in_bits) { |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 48 | DCHECK_EQ(AES, algorithm); |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 49 | |
David Benjamin | 9f832458 | 2022-03-01 23:40:55 | [diff] [blame] | 50 | // Check for supported key sizes. Historically, NSS supported AES-192 while |
| 51 | // BoringSSL did not and this check aligned their behavior. |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 52 | if (key_size_in_bits != 128 && key_size_in_bits != 256) |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 53 | return nullptr; |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 54 | |
pkasting@chromium.org | fdce478 | 2011-11-29 20:06:18 | [diff] [blame] | 55 | size_t key_size_in_bytes = key_size_in_bits / 8; |
| 56 | DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8); |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 57 | |
pkasting@chromium.org | fdce478 | 2011-11-29 20:06:18 | [diff] [blame] | 58 | if (key_size_in_bytes == 0) |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 59 | return nullptr; |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 60 | |
joth@chromium.org | be796bb | 2010-11-18 15:43:43 | [diff] [blame] | 61 | OpenSSLErrStackTracer err_tracer(FROM_HERE); |
thakis | d1a1847 | 2016-04-08 22:30:41 | [diff] [blame] | 62 | std::unique_ptr<SymmetricKey> key(new SymmetricKey); |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 63 | |
David Benjamin | 78bbd02 | 2024-02-09 01:02:49 | [diff] [blame] | 64 | key->key_.resize(key_size_in_bytes); |
| 65 | int rv = RAND_bytes(reinterpret_cast<uint8_t*>(key->key_.data()), |
| 66 | key->key_.size()); |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 67 | return rv == 1 ? std::move(key) : nullptr; |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | // static |
David Davidović | f8cd6a0 | 2018-08-27 14:02:51 | [diff] [blame] | 71 | std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 72 | Algorithm algorithm, |
| 73 | const std::string& password, |
| 74 | const std::string& salt, |
| 75 | size_t iterations, |
| 76 | size_t key_size_in_bits) { |
David Davidović | f8cd6a0 | 2018-08-27 14:02:51 | [diff] [blame] | 77 | if (!CheckDerivationParameters(algorithm, key_size_in_bits)) |
| 78 | return nullptr; |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 79 | |
pkasting@chromium.org | fdce478 | 2011-11-29 20:06:18 | [diff] [blame] | 80 | size_t key_size_in_bytes = key_size_in_bits / 8; |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 81 | |
joth@chromium.org | be796bb | 2010-11-18 15:43:43 | [diff] [blame] | 82 | OpenSSLErrStackTracer err_tracer(FROM_HERE); |
thakis | d1a1847 | 2016-04-08 22:30:41 | [diff] [blame] | 83 | std::unique_ptr<SymmetricKey> key(new SymmetricKey); |
David Benjamin | 78bbd02 | 2024-02-09 01:02:49 | [diff] [blame] | 84 | key->key_.resize(key_size_in_bytes); |
avi | dd373b8 | 2015-12-21 21:34:43 | [diff] [blame] | 85 | int rv = PKCS5_PBKDF2_HMAC_SHA1( |
| 86 | password.data(), password.length(), |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 87 | reinterpret_cast<const uint8_t*>(salt.data()), salt.length(), |
David Benjamin | 78bbd02 | 2024-02-09 01:02:49 | [diff] [blame] | 88 | static_cast<unsigned>(iterations), key->key_.size(), |
| 89 | reinterpret_cast<uint8_t*>(key->key_.data())); |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 90 | return rv == 1 ? std::move(key) : nullptr; |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | // static |
David Davidović | f8cd6a0 | 2018-08-27 14:02:51 | [diff] [blame] | 94 | std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingScrypt( |
| 95 | Algorithm algorithm, |
| 96 | const std::string& password, |
| 97 | const std::string& salt, |
| 98 | size_t cost_parameter, |
| 99 | size_t block_size, |
| 100 | size_t parallelization_parameter, |
| 101 | size_t max_memory_bytes, |
| 102 | size_t key_size_in_bits) { |
| 103 | if (!CheckDerivationParameters(algorithm, key_size_in_bits)) |
| 104 | return nullptr; |
| 105 | |
| 106 | size_t key_size_in_bytes = key_size_in_bits / 8; |
| 107 | |
| 108 | OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 109 | std::unique_ptr<SymmetricKey> key(new SymmetricKey); |
David Benjamin | 78bbd02 | 2024-02-09 01:02:49 | [diff] [blame] | 110 | key->key_.resize(key_size_in_bytes); |
| 111 | int rv = EVP_PBE_scrypt( |
| 112 | password.data(), password.length(), |
| 113 | reinterpret_cast<const uint8_t*>(salt.data()), salt.length(), |
| 114 | cost_parameter, block_size, parallelization_parameter, max_memory_bytes, |
| 115 | reinterpret_cast<uint8_t*>(key->key_.data()), key->key_.size()); |
David Davidović | f8cd6a0 | 2018-08-27 14:02:51 | [diff] [blame] | 116 | return rv == 1 ? std::move(key) : nullptr; |
| 117 | } |
| 118 | |
| 119 | // static |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 120 | std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm, |
| 121 | const std::string& raw_key) { |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 122 | if (algorithm == AES) { |
David Benjamin | 9f832458 | 2022-03-01 23:40:55 | [diff] [blame] | 123 | // Check for supported key sizes. Historically, NSS supported AES-192 while |
| 124 | // BoringSSL did not and this check aligned their behavior. |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 125 | if (raw_key.size() != 128/8 && raw_key.size() != 256/8) |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 126 | return nullptr; |
davidben@chromium.org | a534bab | 2014-07-25 21:04:15 | [diff] [blame] | 127 | } |
| 128 | |
thakis | d1a1847 | 2016-04-08 22:30:41 | [diff] [blame] | 129 | std::unique_ptr<SymmetricKey> key(new SymmetricKey); |
joth@chromium.org | ac0f8be | 2010-11-12 12:03:54 | [diff] [blame] | 130 | key->key_ = raw_key; |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 131 | return key; |
joth@chromium.org | 70372d4 | 2010-10-22 13:12:34 | [diff] [blame] | 132 | } |
| 133 | |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 134 | SymmetricKey::SymmetricKey() = default; |
| 135 | |
rvargas@google.com | 4b559b4d | 2011-04-14 17:37:14 | [diff] [blame] | 136 | } // namespace crypto |