|  | // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "crypto/symmetric_key.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "crypto/openssl_util.h" | 
|  | #include "starboard/types.h" | 
|  | #include "third_party/boringssl/src/include/openssl/evp.h" | 
|  | #include "third_party/boringssl/src/include/openssl/rand.h" | 
|  |  | 
|  | namespace crypto { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | bool CheckDerivationParameters(SymmetricKey::Algorithm algorithm, | 
|  | size_t key_size_in_bits) { | 
|  | switch (algorithm) { | 
|  | case SymmetricKey::AES: | 
|  | // Whitelist supported key sizes to avoid accidentally relying on | 
|  | // algorithms available in NSS but not BoringSSL and vice | 
|  | // versa. Note that BoringSSL does not support AES-192. | 
|  | return key_size_in_bits == 128 || key_size_in_bits == 256; | 
|  | case SymmetricKey::HMAC_SHA1: | 
|  | return key_size_in_bits % 8 == 0 && key_size_in_bits != 0; | 
|  | } | 
|  |  | 
|  | NOTREACHED(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | SymmetricKey::~SymmetricKey() { | 
|  | std::fill(key_.begin(), key_.end(), '\0');  // Zero out the confidential key. | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey( | 
|  | Algorithm algorithm, | 
|  | size_t key_size_in_bits) { | 
|  | DCHECK_EQ(AES, algorithm); | 
|  |  | 
|  | // Whitelist supported key sizes to avoid accidentaly relying on | 
|  | // algorithms available in NSS but not BoringSSL and vice | 
|  | // versa. Note that BoringSSL does not support AES-192. | 
|  | if (key_size_in_bits != 128 && key_size_in_bits != 256) | 
|  | return nullptr; | 
|  |  | 
|  | size_t key_size_in_bytes = key_size_in_bits / 8; | 
|  | DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8); | 
|  |  | 
|  | if (key_size_in_bytes == 0) | 
|  | return nullptr; | 
|  |  | 
|  | OpenSSLErrStackTracer err_tracer(FROM_HERE); | 
|  | std::unique_ptr<SymmetricKey> key(new SymmetricKey); | 
|  | uint8_t* key_data = reinterpret_cast<uint8_t*>( | 
|  | base::WriteInto(&key->key_, key_size_in_bytes + 1)); | 
|  |  | 
|  | int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes)); | 
|  | return rv == 1 ? std::move(key) : nullptr; | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( | 
|  | Algorithm algorithm, | 
|  | const std::string& password, | 
|  | const std::string& salt, | 
|  | size_t iterations, | 
|  | size_t key_size_in_bits) { | 
|  | if (!CheckDerivationParameters(algorithm, key_size_in_bits)) | 
|  | return nullptr; | 
|  |  | 
|  | size_t key_size_in_bytes = key_size_in_bits / 8; | 
|  |  | 
|  | OpenSSLErrStackTracer err_tracer(FROM_HERE); | 
|  | std::unique_ptr<SymmetricKey> key(new SymmetricKey); | 
|  | uint8_t* key_data = reinterpret_cast<uint8_t*>( | 
|  | base::WriteInto(&key->key_, key_size_in_bytes + 1)); | 
|  |  | 
|  | int rv = PKCS5_PBKDF2_HMAC_SHA1( | 
|  | password.data(), password.length(), | 
|  | reinterpret_cast<const uint8_t*>(salt.data()), salt.length(), | 
|  | static_cast<unsigned>(iterations), | 
|  | key_size_in_bytes, key_data); | 
|  | return rv == 1 ? std::move(key) : nullptr; | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<SymmetricKey> SymmetricKey::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) { | 
|  | if (!CheckDerivationParameters(algorithm, key_size_in_bits)) | 
|  | return nullptr; | 
|  |  | 
|  | size_t key_size_in_bytes = key_size_in_bits / 8; | 
|  |  | 
|  | OpenSSLErrStackTracer err_tracer(FROM_HERE); | 
|  | std::unique_ptr<SymmetricKey> key(new SymmetricKey); | 
|  | uint8_t* key_data = reinterpret_cast<uint8_t*>( | 
|  | base::WriteInto(&key->key_, key_size_in_bytes + 1)); | 
|  |  | 
|  | int rv = EVP_PBE_scrypt(password.data(), password.length(), | 
|  | reinterpret_cast<const uint8_t*>(salt.data()), | 
|  | salt.length(), cost_parameter, block_size, | 
|  | parallelization_parameter, max_memory_bytes, key_data, | 
|  | key_size_in_bytes); | 
|  | return rv == 1 ? std::move(key) : nullptr; | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm, | 
|  | const std::string& raw_key) { | 
|  | if (algorithm == AES) { | 
|  | // Whitelist supported key sizes to avoid accidentaly relying on | 
|  | // algorithms available in NSS but not BoringSSL and vice | 
|  | // versa. Note that BoringSSL does not support AES-192. | 
|  | if (raw_key.size() != 128/8 && raw_key.size() != 256/8) | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<SymmetricKey> key(new SymmetricKey); | 
|  | key->key_ = raw_key; | 
|  | return key; | 
|  | } | 
|  |  | 
|  | SymmetricKey::SymmetricKey() = default; | 
|  |  | 
|  | }  // namespace crypto |