blob: 52af667645b39ee7703ce7b74ff20455b9e8acae [file] [log] [blame]
Benjamin Wrightb3f887b2018-10-30 13:53:30 -07001/*
2 * Copyright 2018 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "rtc_base/openssl_key_derivation_hkdf.h"
12
13#include <openssl/digest.h>
14#include <openssl/err.h>
15#include <openssl/hkdf.h>
16#include <openssl/sha.h>
17
18#include <algorithm>
19#include <utility>
20
21#include "rtc_base/buffer.h"
22#include "rtc_base/openssl.h"
23
24namespace rtc {
25
26OpenSSLKeyDerivationHKDF::OpenSSLKeyDerivationHKDF() = default;
27OpenSSLKeyDerivationHKDF::~OpenSSLKeyDerivationHKDF() = default;
28
29const size_t OpenSSLKeyDerivationHKDF::kMinKeyByteSize = 16;
30const size_t OpenSSLKeyDerivationHKDF::kMaxKeyByteSize =
31 255 * SHA256_DIGEST_LENGTH;
32const size_t OpenSSLKeyDerivationHKDF::kMinSecretByteSize = 16;
33
34absl::optional<ZeroOnFreeBuffer<uint8_t>> OpenSSLKeyDerivationHKDF::DeriveKey(
35 rtc::ArrayView<const uint8_t> secret,
36 rtc::ArrayView<const uint8_t> salt,
37 rtc::ArrayView<const uint8_t> label,
38 size_t derived_key_byte_size) {
39 // Prevent deriving less than 128 bits of key material or more than the max.
40 if (derived_key_byte_size < kMinKeyByteSize ||
41 derived_key_byte_size > kMaxKeyByteSize) {
42 return absl::nullopt;
43 }
44 // The secret must reach the minimum number of bits to be secure.
45 if (secret.data() == nullptr || secret.size() < kMinSecretByteSize) {
46 return absl::nullopt;
47 }
48 // Empty labels are always invalid in derivation.
49 if (label.data() == nullptr || label.size() == 0) {
50 return absl::nullopt;
51 }
52 // If a random salt is not provided use all zeros.
53 rtc::Buffer salt_buffer;
54 if (salt.data() == nullptr || salt.size() == 0) {
55 salt_buffer.SetSize(SHA256_DIGEST_LENGTH);
56 std::fill(salt_buffer.begin(), salt_buffer.end(), 0);
57 salt = salt_buffer;
58 }
59 // This buffer will erase itself on release.
60 ZeroOnFreeBuffer<uint8_t> derived_key_buffer(derived_key_byte_size, 0);
61 if (!HKDF(derived_key_buffer.data(), derived_key_buffer.size(), EVP_sha256(),
62 secret.data(), secret.size(), salt.data(), salt.size(),
63 label.data(), label.size())) {
64 return absl::nullopt;
65 }
66 return absl::optional<ZeroOnFreeBuffer<uint8_t>>(
67 std::move(derived_key_buffer));
68}
69
70} // namespace rtc