Upload upstream chromium 67.0.3396
[platform/framework/web/chromium-efl.git] / crypto / hkdf.cc
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.
4
5 #include "crypto/hkdf.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11
12 #include "base/logging.h"
13 #include "crypto/hmac.h"
14
15 namespace crypto {
16
17 const size_t kSHA256HashLength = 32;
18
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)
25     : HKDF(secret,
26            salt,
27            info,
28            key_bytes_to_generate,
29            key_bytes_to_generate,
30            iv_bytes_to_generate,
31            iv_bytes_to_generate,
32            subkey_secret_bytes_to_generate) {}
33
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));
49   }
50
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);
55   DCHECK(result);
56
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));
61   DCHECK(result);
62
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;
70   const size_t n =
71       (material_length + kSHA256HashLength - 1) / kSHA256HashLength;
72   DCHECK_LT(n, 256u);
73
74   output_.resize(n * kSHA256HashLength);
75   base::StringPiece previous;
76
77   std::unique_ptr<char[]> buf(new char[kSHA256HashLength + info.size() + 1]);
78   uint8_t digest[kSHA256HashLength];
79
80   HMAC hmac(HMAC::SHA256);
81   result = hmac.Init(prk, sizeof(prk));
82   DCHECK(result);
83
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());
88     j += info.size();
89     buf[j++] = static_cast<char>(i + 1);
90
91     result = hmac.Sign(base::StringPiece(buf.get(), j), digest, sizeof(digest));
92     DCHECK(result);
93
94     memcpy(&output_[i*sizeof(digest)], digest, sizeof(digest));
95     previous = base::StringPiece(reinterpret_cast<char*>(digest),
96                                  sizeof(digest));
97   }
98
99   size_t j = 0;
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;
107   }
108
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;
113   }
114
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;
119   }
120
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;
125   }
126
127   if (subkey_secret_bytes_to_generate) {
128     subkey_secret_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
129                                        subkey_secret_bytes_to_generate);
130   }
131 }
132
133 HKDF::~HKDF() = default;
134
135 }  // namespace crypto