1 // Copyright (c) 2013 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.
5 #include "crypto/hkdf.h"
12 #include "base/logging.h"
13 #include "crypto/hmac.h"
17 const size_t kSHA256HashLength = 32;
19 HKDF::HKDF(base::StringPiece secret,
20 base::StringPiece salt,
21 base::StringPiece info,
22 size_t key_bytes_to_generate,
23 size_t iv_bytes_to_generate,
24 size_t subkey_secret_bytes_to_generate)
28 key_bytes_to_generate,
29 key_bytes_to_generate,
32 subkey_secret_bytes_to_generate) {}
34 HKDF::HKDF(base::StringPiece secret,
35 base::StringPiece salt,
36 base::StringPiece info,
37 size_t client_key_bytes_to_generate,
38 size_t server_key_bytes_to_generate,
39 size_t client_iv_bytes_to_generate,
40 size_t server_iv_bytes_to_generate,
41 size_t subkey_secret_bytes_to_generate) {
42 // https://tools.ietf.org/html/rfc5869#section-2.2
43 base::StringPiece actual_salt = salt;
44 char zeros[kSHA256HashLength];
45 if (actual_salt.empty()) {
46 // If salt is not given, HashLength zeros are used.
47 memset(zeros, 0, sizeof(zeros));
48 actual_salt.set(zeros, sizeof(zeros));
51 // Perform the Extract step to transform the input key and
52 // salt into the pseudorandom key (PRK) used for Expand.
53 HMAC prk_hmac(HMAC::SHA256);
54 bool result = prk_hmac.Init(actual_salt);
57 // |prk| is a pseudorandom key (of kSHA256HashLength octets).
58 uint8_t prk[kSHA256HashLength];
59 DCHECK_EQ(sizeof(prk), prk_hmac.DigestLength());
60 result = prk_hmac.Sign(secret, prk, sizeof(prk));
63 // https://tools.ietf.org/html/rfc5869#section-2.3
64 // Perform the Expand phase to turn the pseudorandom key
65 // and info into the output keying material.
66 const size_t material_length =
67 client_key_bytes_to_generate + client_iv_bytes_to_generate +
68 server_key_bytes_to_generate + server_iv_bytes_to_generate +
69 subkey_secret_bytes_to_generate;
71 (material_length + kSHA256HashLength - 1) / kSHA256HashLength;
74 output_.resize(n * kSHA256HashLength);
75 base::StringPiece previous;
77 std::unique_ptr<char[]> buf(new char[kSHA256HashLength + info.size() + 1]);
78 uint8_t digest[kSHA256HashLength];
80 HMAC hmac(HMAC::SHA256);
81 result = hmac.Init(prk, sizeof(prk));
84 for (size_t i = 0; i < n; i++) {
85 memcpy(buf.get(), previous.data(), previous.size());
86 size_t j = previous.size();
87 memcpy(buf.get() + j, info.data(), info.size());
89 buf[j++] = static_cast<char>(i + 1);
91 result = hmac.Sign(base::StringPiece(buf.get(), j), digest, sizeof(digest));
94 memcpy(&output_[i*sizeof(digest)], digest, sizeof(digest));
95 previous = base::StringPiece(reinterpret_cast<char*>(digest),
100 // On Windows, when the size of output_ is zero, dereference of 0'th element
101 // results in a crash. C++11 solves this problem by adding a data() getter
102 // method to std::vector.
103 if (client_key_bytes_to_generate) {
104 client_write_key_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
105 client_key_bytes_to_generate);
106 j += client_key_bytes_to_generate;
109 if (server_key_bytes_to_generate) {
110 server_write_key_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
111 server_key_bytes_to_generate);
112 j += server_key_bytes_to_generate;
115 if (client_iv_bytes_to_generate) {
116 client_write_iv_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
117 client_iv_bytes_to_generate);
118 j += client_iv_bytes_to_generate;
121 if (server_iv_bytes_to_generate) {
122 server_write_iv_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
123 server_iv_bytes_to_generate);
124 j += server_iv_bytes_to_generate;
127 if (subkey_secret_bytes_to_generate) {
128 subkey_secret_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
129 subkey_secret_bytes_to_generate);
133 HKDF::~HKDF() = default;
135 } // namespace crypto