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