pbkdf2.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2015 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 <stdint.h>
  5. #include <memory>
  6. #include "base/containers/span.h"
  7. #include "components/webcrypto/algorithm_implementation.h"
  8. #include "components/webcrypto/algorithms/secret_key_util.h"
  9. #include "components/webcrypto/algorithms/util.h"
  10. #include "components/webcrypto/blink_key_handle.h"
  11. #include "components/webcrypto/status.h"
  12. #include "crypto/openssl_util.h"
  13. #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
  14. #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
  15. #include "third_party/boringssl/src/include/openssl/evp.h"
  16. namespace webcrypto {
  17. namespace {
  18. const blink::WebCryptoKeyUsageMask kAllKeyUsages =
  19. blink::kWebCryptoKeyUsageDeriveKey | blink::kWebCryptoKeyUsageDeriveBits;
  20. class Pbkdf2Implementation : public AlgorithmImplementation {
  21. public:
  22. Pbkdf2Implementation() {}
  23. Status ImportKey(blink::WebCryptoKeyFormat format,
  24. base::span<const uint8_t> key_data,
  25. const blink::WebCryptoAlgorithm& algorithm,
  26. bool extractable,
  27. blink::WebCryptoKeyUsageMask usages,
  28. blink::WebCryptoKey* key) const override {
  29. switch (format) {
  30. case blink::kWebCryptoKeyFormatRaw:
  31. return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
  32. default:
  33. return Status::ErrorUnsupportedImportKeyFormat();
  34. }
  35. }
  36. Status ImportKeyRaw(base::span<const uint8_t> key_data,
  37. const blink::WebCryptoAlgorithm& algorithm,
  38. bool extractable,
  39. blink::WebCryptoKeyUsageMask usages,
  40. blink::WebCryptoKey* key) const {
  41. Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
  42. if (status.IsError())
  43. return status;
  44. if (extractable)
  45. return Status::ErrorImportExtractableKdfKey();
  46. const blink::WebCryptoKeyAlgorithm key_algorithm =
  47. blink::WebCryptoKeyAlgorithm::CreateWithoutParams(
  48. blink::kWebCryptoAlgorithmIdPbkdf2);
  49. return CreateWebCryptoSecretKey(key_data, key_algorithm, extractable,
  50. usages, key);
  51. }
  52. Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm,
  53. const blink::WebCryptoKey& base_key,
  54. bool has_optional_length_bits,
  55. unsigned int optional_length_bits,
  56. std::vector<uint8_t>* derived_bytes) const override {
  57. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  58. if (!has_optional_length_bits)
  59. return Status::ErrorPbkdf2DeriveBitsLengthNotSpecified();
  60. if (optional_length_bits % 8)
  61. return Status::ErrorPbkdf2InvalidLength();
  62. // According to RFC 2898 "dkLength" (derived key length) is
  63. // described as being a "positive integer", so it is an error for
  64. // it to be 0.
  65. if (optional_length_bits == 0)
  66. return Status::ErrorPbkdf2DeriveBitsLengthZero();
  67. const blink::WebCryptoPbkdf2Params* params = algorithm.Pbkdf2Params();
  68. if (params->Iterations() == 0)
  69. return Status::ErrorPbkdf2Iterations0();
  70. const EVP_MD* digest_algorithm = GetDigest(params->GetHash());
  71. if (!digest_algorithm)
  72. return Status::ErrorUnsupported();
  73. unsigned int keylen_bytes = optional_length_bits / 8;
  74. derived_bytes->resize(keylen_bytes);
  75. const std::vector<uint8_t>& password = GetSymmetricKeyData(base_key);
  76. if (!PKCS5_PBKDF2_HMAC(
  77. reinterpret_cast<const char*>(password.data()), password.size(),
  78. params->Salt().data(), params->Salt().size(), params->Iterations(),
  79. digest_algorithm, keylen_bytes, derived_bytes->data())) {
  80. return Status::OperationError();
  81. }
  82. return Status::Success();
  83. }
  84. Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
  85. blink::WebCryptoKeyType type,
  86. bool extractable,
  87. blink::WebCryptoKeyUsageMask usages,
  88. base::span<const uint8_t> key_data,
  89. blink::WebCryptoKey* key) const override {
  90. if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeNone ||
  91. type != blink::kWebCryptoKeyTypeSecret)
  92. return Status::ErrorUnexpected();
  93. // NOTE: Unlike ImportKeyRaw(), this does not enforce extractable==false.
  94. // This is intentional. Although keys cannot currently be created with
  95. // extractable==true, earlier implementations permitted this, so
  96. // de-serialization by structured clone should not reject them.
  97. return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages,
  98. key);
  99. }
  100. Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
  101. bool* has_length_bits,
  102. unsigned int* length_bits) const override {
  103. *has_length_bits = false;
  104. return Status::Success();
  105. }
  106. };
  107. } // namespace
  108. std::unique_ptr<AlgorithmImplementation> CreatePbkdf2Implementation() {
  109. return std::make_unique<Pbkdf2Implementation>();
  110. }
  111. } // namespace webcrypto