Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      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/logging.h"
     14 #include "base/strings/string_util.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 SymmetricKey::~SymmetricKey() {
     22   std::fill(key_.begin(), key_.end(), '\0');  // Zero out the confidential key.
     23 }
     24 
     25 // static
     26 std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey(
     27     Algorithm algorithm,
     28     size_t key_size_in_bits) {
     29   DCHECK_EQ(AES, algorithm);
     30 
     31   // Whitelist supported key sizes to avoid accidentaly relying on
     32   // algorithms available in NSS but not BoringSSL and vice
     33   // versa. Note that BoringSSL does not support AES-192.
     34   if (key_size_in_bits != 128 && key_size_in_bits != 256)
     35     return nullptr;
     36 
     37   size_t key_size_in_bytes = key_size_in_bits / 8;
     38   DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
     39 
     40   if (key_size_in_bytes == 0)
     41     return nullptr;
     42 
     43   OpenSSLErrStackTracer err_tracer(FROM_HERE);
     44   std::unique_ptr<SymmetricKey> key(new SymmetricKey);
     45   uint8_t* key_data = reinterpret_cast<uint8_t*>(
     46       base::WriteInto(&key->key_, key_size_in_bytes + 1));
     47 
     48   int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes));
     49   return rv == 1 ? std::move(key) : nullptr;
     50 }
     51 
     52 // static
     53 std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPassword(
     54     Algorithm algorithm,
     55     const std::string& password,
     56     const std::string& salt,
     57     size_t iterations,
     58     size_t key_size_in_bits) {
     59   DCHECK(algorithm == AES || algorithm == HMAC_SHA1);
     60 
     61   if (algorithm == AES) {
     62     // Whitelist supported key sizes to avoid accidentaly relying on
     63     // algorithms available in NSS but not BoringSSL and vice
     64     // versa. Note that BoringSSL does not support AES-192.
     65     if (key_size_in_bits != 128 && key_size_in_bits != 256)
     66       return nullptr;
     67   }
     68 
     69   size_t key_size_in_bytes = key_size_in_bits / 8;
     70   DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
     71 
     72   if (key_size_in_bytes == 0)
     73     return nullptr;
     74 
     75   OpenSSLErrStackTracer err_tracer(FROM_HERE);
     76   std::unique_ptr<SymmetricKey> key(new SymmetricKey);
     77   uint8_t* key_data = reinterpret_cast<uint8_t*>(
     78       base::WriteInto(&key->key_, key_size_in_bytes + 1));
     79   int rv = PKCS5_PBKDF2_HMAC_SHA1(
     80       password.data(), password.length(),
     81       reinterpret_cast<const uint8_t*>(salt.data()), salt.length(),
     82       static_cast<unsigned>(iterations),
     83       key_size_in_bytes, key_data);
     84   return rv == 1 ? std::move(key) : nullptr;
     85 }
     86 
     87 // static
     88 std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm,
     89                                                    const std::string& raw_key) {
     90   if (algorithm == AES) {
     91     // Whitelist supported key sizes to avoid accidentaly relying on
     92     // algorithms available in NSS but not BoringSSL and vice
     93     // versa. Note that BoringSSL does not support AES-192.
     94     if (raw_key.size() != 128/8 && raw_key.size() != 256/8)
     95       return nullptr;
     96   }
     97 
     98   std::unique_ptr<SymmetricKey> key(new SymmetricKey);
     99   key->key_ = raw_key;
    100   return key;
    101 }
    102 
    103 SymmetricKey::SymmetricKey() = default;
    104 
    105 }  // namespace crypto
    106