• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "crypto/hmac.h"
10 
11 namespace crypto {
12 
13 const size_t kSHA256HashLength = 32;
14 
HKDF(const base::StringPiece & secret,const base::StringPiece & salt,const base::StringPiece & info,size_t key_bytes_to_generate,size_t iv_bytes_to_generate,size_t subkey_secret_bytes_to_generate)15 HKDF::HKDF(const base::StringPiece& secret,
16            const base::StringPiece& salt,
17            const base::StringPiece& info,
18            size_t key_bytes_to_generate,
19            size_t iv_bytes_to_generate,
20            size_t subkey_secret_bytes_to_generate) {
21   // https://tools.ietf.org/html/rfc5869#section-2.2
22   base::StringPiece actual_salt = salt;
23   char zeros[kSHA256HashLength];
24   if (actual_salt.empty()) {
25     // If salt is not given, HashLength zeros are used.
26     memset(zeros, 0, sizeof(zeros));
27     actual_salt.set(zeros, sizeof(zeros));
28   }
29 
30   // Perform the Extract step to transform the input key and
31   // salt into the pseudorandom key (PRK) used for Expand.
32   HMAC prk_hmac(HMAC::SHA256);
33   bool result = prk_hmac.Init(actual_salt);
34   DCHECK(result);
35 
36   // |prk| is a pseudorandom key (of kSHA256HashLength octets).
37   uint8 prk[kSHA256HashLength];
38   DCHECK_EQ(sizeof(prk), prk_hmac.DigestLength());
39   result = prk_hmac.Sign(secret, prk, sizeof(prk));
40   DCHECK(result);
41 
42   // https://tools.ietf.org/html/rfc5869#section-2.3
43   // Perform the Expand phase to turn the pseudorandom key
44   // and info into the output keying material.
45   const size_t material_length = 2 * key_bytes_to_generate +
46                                  2 * iv_bytes_to_generate +
47                                  subkey_secret_bytes_to_generate;
48   const size_t n = (material_length + kSHA256HashLength-1) /
49                    kSHA256HashLength;
50   DCHECK_LT(n, 256u);
51 
52   output_.resize(n * kSHA256HashLength);
53   base::StringPiece previous;
54 
55   scoped_ptr<char[]> buf(new char[kSHA256HashLength + info.size() + 1]);
56   uint8 digest[kSHA256HashLength];
57 
58   HMAC hmac(HMAC::SHA256);
59   result = hmac.Init(prk, sizeof(prk));
60   DCHECK(result);
61 
62   for (size_t i = 0; i < n; i++) {
63     memcpy(buf.get(), previous.data(), previous.size());
64     size_t j = previous.size();
65     memcpy(buf.get() + j, info.data(), info.size());
66     j += info.size();
67     buf[j++] = static_cast<char>(i + 1);
68 
69     result = hmac.Sign(base::StringPiece(buf.get(), j), digest, sizeof(digest));
70     DCHECK(result);
71 
72     memcpy(&output_[i*sizeof(digest)], digest, sizeof(digest));
73     previous = base::StringPiece(reinterpret_cast<char*>(digest),
74                                  sizeof(digest));
75   }
76 
77   size_t j = 0;
78   // On Windows, when the size of output_ is zero, dereference of 0'th element
79   // results in a crash. C++11 solves this problem by adding a data() getter
80   // method to std::vector.
81   if (key_bytes_to_generate) {
82     client_write_key_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
83                                           key_bytes_to_generate);
84     j += key_bytes_to_generate;
85     server_write_key_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
86                                           key_bytes_to_generate);
87     j += key_bytes_to_generate;
88   }
89 
90   if (iv_bytes_to_generate) {
91     client_write_iv_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
92                                          iv_bytes_to_generate);
93     j += iv_bytes_to_generate;
94     server_write_iv_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
95                                          iv_bytes_to_generate);
96     j += iv_bytes_to_generate;
97   }
98   if (subkey_secret_bytes_to_generate) {
99     subkey_secret_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]),
100                                        subkey_secret_bytes_to_generate);
101   }
102 }
103 
~HKDF()104 HKDF::~HKDF() {
105 }
106 
107 }  // namespace crypto
108