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