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