xref: /aosp_15_r20/external/cronet/crypto/symmetric_key.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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