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/openssl_util.h"
16 #include "third_party/boringssl/src/include/openssl/evp.h"
17 #include "third_party/boringssl/src/include/openssl/rand.h"
18
19 namespace crypto {
20
21 namespace {
22
CheckDerivationParameters(SymmetricKey::Algorithm algorithm,size_t key_size_in_bits)23 bool CheckDerivationParameters(SymmetricKey::Algorithm algorithm,
24 size_t key_size_in_bits) {
25 switch (algorithm) {
26 case SymmetricKey::AES:
27 // Check for supported key sizes. Historically, NSS supported AES-192
28 // while BoringSSL did not and this check aligned their behavior.
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
~SymmetricKey()40 SymmetricKey::~SymmetricKey() {
41 std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key.
42 }
43
44 // static
GenerateRandomKey(Algorithm algorithm,size_t key_size_in_bits)45 std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey(
46 Algorithm algorithm,
47 size_t key_size_in_bits) {
48 DCHECK_EQ(AES, algorithm);
49
50 // Check for supported key sizes. Historically, NSS supported AES-192 while
51 // BoringSSL did not and this check aligned their behavior.
52 if (key_size_in_bits != 128 && key_size_in_bits != 256)
53 return nullptr;
54
55 size_t key_size_in_bytes = key_size_in_bits / 8;
56 DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
57
58 if (key_size_in_bytes == 0)
59 return nullptr;
60
61 OpenSSLErrStackTracer err_tracer(FROM_HERE);
62 std::unique_ptr<SymmetricKey> key(new SymmetricKey);
63
64 key->key_.resize(key_size_in_bytes);
65 int rv = RAND_bytes(reinterpret_cast<uint8_t*>(key->key_.data()),
66 key->key_.size());
67 return rv == 1 ? std::move(key) : nullptr;
68 }
69
70 // static
DeriveKeyFromPasswordUsingPbkdf2(Algorithm algorithm,const std::string & password,const std::string & salt,size_t iterations,size_t key_size_in_bits)71 std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
72 Algorithm algorithm,
73 const std::string& password,
74 const std::string& salt,
75 size_t iterations,
76 size_t key_size_in_bits) {
77 if (!CheckDerivationParameters(algorithm, key_size_in_bits))
78 return nullptr;
79
80 size_t key_size_in_bytes = key_size_in_bits / 8;
81
82 OpenSSLErrStackTracer err_tracer(FROM_HERE);
83 std::unique_ptr<SymmetricKey> key(new SymmetricKey);
84 key->key_.resize(key_size_in_bytes);
85 int rv = PKCS5_PBKDF2_HMAC_SHA1(
86 password.data(), password.length(),
87 reinterpret_cast<const uint8_t*>(salt.data()), salt.length(),
88 static_cast<unsigned>(iterations), key->key_.size(),
89 reinterpret_cast<uint8_t*>(key->key_.data()));
90 return rv == 1 ? std::move(key) : nullptr;
91 }
92
93 // static
DeriveKeyFromPasswordUsingScrypt(Algorithm 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)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);
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());
116 return rv == 1 ? std::move(key) : nullptr;
117 }
118
119 // static
Import(Algorithm algorithm,const std::string & raw_key)120 std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm,
121 const std::string& raw_key) {
122 if (algorithm == AES) {
123 // Check for supported key sizes. Historically, NSS supported AES-192 while
124 // BoringSSL did not and this check aligned their behavior.
125 if (raw_key.size() != 128/8 && raw_key.size() != 256/8)
126 return nullptr;
127 }
128
129 std::unique_ptr<SymmetricKey> key(new SymmetricKey);
130 key->key_ = raw_key;
131 return key;
132 }
133
134 SymmetricKey::SymmetricKey() = default;
135
136 } // namespace crypto
137