Home | History | Annotate | Download | only in crypto
      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
    100