symmetric_key.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. #include "crypto/symmetric_key.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <algorithm>
  8. #include <utility>
  9. #include "base/check_op.h"
  10. #include "base/notreached.h"
  11. #include "base/strings/string_util.h"
  12. #include "crypto/openssl_util.h"
  13. #include "third_party/boringssl/src/include/openssl/evp.h"
  14. #include "third_party/boringssl/src/include/openssl/rand.h"
  15. namespace crypto {
  16. namespace {
  17. bool CheckDerivationParameters(SymmetricKey::Algorithm algorithm,
  18. size_t key_size_in_bits) {
  19. switch (algorithm) {
  20. case SymmetricKey::AES:
  21. // Check for supported key sizes. Historically, NSS supported AES-192
  22. // while BoringSSL did not and this check aligned their behavior.
  23. return key_size_in_bits == 128 || key_size_in_bits == 256;
  24. case SymmetricKey::HMAC_SHA1:
  25. return key_size_in_bits % 8 == 0 && key_size_in_bits != 0;
  26. }
  27. NOTREACHED();
  28. return false;
  29. }
  30. } // namespace
  31. SymmetricKey::~SymmetricKey() {
  32. std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key.
  33. }
  34. // static
  35. std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey(
  36. Algorithm algorithm,
  37. size_t key_size_in_bits) {
  38. DCHECK_EQ(AES, algorithm);
  39. // Check for supported key sizes. Historically, NSS supported AES-192 while
  40. // BoringSSL did not and this check aligned their behavior.
  41. if (key_size_in_bits != 128 && key_size_in_bits != 256)
  42. return nullptr;
  43. size_t key_size_in_bytes = key_size_in_bits / 8;
  44. DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
  45. if (key_size_in_bytes == 0)
  46. return nullptr;
  47. OpenSSLErrStackTracer err_tracer(FROM_HERE);
  48. std::unique_ptr<SymmetricKey> key(new SymmetricKey);
  49. uint8_t* key_data = reinterpret_cast<uint8_t*>(
  50. base::WriteInto(&key->key_, key_size_in_bytes + 1));
  51. int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes));
  52. return rv == 1 ? std::move(key) : nullptr;
  53. }
  54. // static
  55. std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
  56. Algorithm algorithm,
  57. const std::string& password,
  58. const std::string& salt,
  59. size_t iterations,
  60. size_t key_size_in_bits) {
  61. if (!CheckDerivationParameters(algorithm, key_size_in_bits))
  62. return nullptr;
  63. size_t key_size_in_bytes = key_size_in_bits / 8;
  64. OpenSSLErrStackTracer err_tracer(FROM_HERE);
  65. std::unique_ptr<SymmetricKey> key(new SymmetricKey);
  66. uint8_t* key_data = reinterpret_cast<uint8_t*>(
  67. base::WriteInto(&key->key_, key_size_in_bytes + 1));
  68. int rv = PKCS5_PBKDF2_HMAC_SHA1(
  69. password.data(), password.length(),
  70. reinterpret_cast<const uint8_t*>(salt.data()), salt.length(),
  71. static_cast<unsigned>(iterations),
  72. key_size_in_bytes, key_data);
  73. return rv == 1 ? std::move(key) : nullptr;
  74. }
  75. // static
  76. std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingScrypt(
  77. Algorithm algorithm,
  78. const std::string& password,
  79. const std::string& salt,
  80. size_t cost_parameter,
  81. size_t block_size,
  82. size_t parallelization_parameter,
  83. size_t max_memory_bytes,
  84. size_t key_size_in_bits) {
  85. if (!CheckDerivationParameters(algorithm, key_size_in_bits))
  86. return nullptr;
  87. size_t key_size_in_bytes = key_size_in_bits / 8;
  88. OpenSSLErrStackTracer err_tracer(FROM_HERE);
  89. std::unique_ptr<SymmetricKey> key(new SymmetricKey);
  90. uint8_t* key_data = reinterpret_cast<uint8_t*>(
  91. base::WriteInto(&key->key_, key_size_in_bytes + 1));
  92. int rv = EVP_PBE_scrypt(password.data(), password.length(),
  93. reinterpret_cast<const uint8_t*>(salt.data()),
  94. salt.length(), cost_parameter, block_size,
  95. parallelization_parameter, max_memory_bytes, key_data,
  96. key_size_in_bytes);
  97. return rv == 1 ? std::move(key) : nullptr;
  98. }
  99. // static
  100. std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm,
  101. const std::string& raw_key) {
  102. if (algorithm == AES) {
  103. // Check for supported key sizes. Historically, NSS supported AES-192 while
  104. // BoringSSL did not and this check aligned their behavior.
  105. if (raw_key.size() != 128/8 && raw_key.size() != 256/8)
  106. return nullptr;
  107. }
  108. std::unique_ptr<SymmetricKey> key(new SymmetricKey);
  109. key->key_ = raw_key;
  110. return key;
  111. }
  112. SymmetricKey::SymmetricKey() = default;
  113. } // namespace crypto