forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Relanding Porting of HKDF changes from server.
Added a2b_hex function to move common code in hkdf_unittest.cc and to make it similar to CL - 40300624. Merge internal CL: 40300624 Original approved CL: https://chromiumcodereview.appspot.com/12326029/ R=agl@chromium.org, rsleevi@chromium.org Review URL: https://chromiumcodereview.appspot.com/12335045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184306 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
rtenneti@chromium.org
committed
Feb 23, 2013
1 parent
8bdcb66
commit 48b581d
Showing
4 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright (c) 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "crypto/hkdf.h" | ||
|
||
#include "base/logging.h" | ||
#include "crypto/hmac.h" | ||
|
||
namespace crypto { | ||
|
||
const size_t kSHA256HashLength = 32; | ||
|
||
HKDF::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) { | ||
// https://tools.ietf.org/html/rfc5869#section-2.2 | ||
base::StringPiece actual_salt = salt; | ||
char zeros[kSHA256HashLength]; | ||
if (actual_salt.empty()) { | ||
// If salt is not given, HashLength zeros are used. | ||
memset(zeros, 0, sizeof(zeros)); | ||
actual_salt.set(zeros, sizeof(zeros)); | ||
} | ||
|
||
// Perform the Extract step to transform the input key and | ||
// salt into the pseudorandom key (PRK) used for Expand. | ||
HMAC prk_hmac(HMAC::SHA256); | ||
bool result = prk_hmac.Init(actual_salt); | ||
DCHECK(result); | ||
|
||
// |prk| is a pseudorandom key (of kSHA256HashLength octets). | ||
uint8 prk[kSHA256HashLength]; | ||
DCHECK_EQ(sizeof(prk), prk_hmac.DigestLength()); | ||
result = prk_hmac.Sign(secret, prk, sizeof(prk)); | ||
DCHECK(result); | ||
|
||
// https://tools.ietf.org/html/rfc5869#section-2.3 | ||
// Perform the Expand phase to turn the pseudorandom key | ||
// and info into the output keying material. | ||
const size_t material_length = | ||
2*key_bytes_to_generate + 2*iv_bytes_to_generate; | ||
const size_t n = (material_length + kSHA256HashLength-1) / | ||
kSHA256HashLength; | ||
DCHECK_LT(n, 256u); | ||
|
||
output_.resize(n * kSHA256HashLength); | ||
base::StringPiece previous; | ||
|
||
char* buf = new char[kSHA256HashLength + info.size() + 1]; | ||
uint8 digest[kSHA256HashLength]; | ||
|
||
HMAC hmac(HMAC::SHA256); | ||
result = hmac.Init(prk, sizeof(prk)); | ||
DCHECK(result); | ||
|
||
for (size_t i = 0; i < n; i++) { | ||
memcpy(buf, previous.data(), previous.size()); | ||
size_t j = previous.size(); | ||
memcpy(buf + j, info.data(), info.size()); | ||
j += info.size(); | ||
buf[j++] = static_cast<char>((i + 1) & 0xFF); | ||
|
||
result = hmac.Sign(base::StringPiece(buf, j), digest, sizeof(digest)); | ||
DCHECK(result); | ||
|
||
memcpy(&output_[i*sizeof(digest)], digest, sizeof(digest)); | ||
previous = base::StringPiece(reinterpret_cast<char*>(digest), | ||
sizeof(digest)); | ||
} | ||
|
||
size_t j = 0; | ||
client_write_key_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]), | ||
key_bytes_to_generate); | ||
j += key_bytes_to_generate; | ||
server_write_key_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]), | ||
key_bytes_to_generate); | ||
j += key_bytes_to_generate; | ||
client_write_iv_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]), | ||
iv_bytes_to_generate); | ||
j += iv_bytes_to_generate; | ||
server_write_iv_ = base::StringPiece(reinterpret_cast<char*>(&output_[j]), | ||
iv_bytes_to_generate); | ||
delete[] buf; | ||
} | ||
|
||
HKDF::~HKDF() { | ||
} | ||
|
||
} // namespace crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright (c) 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CRYPTO_HKDF_H_ | ||
#define CRYPTO_HKDF_H_ | ||
|
||
#include <vector> | ||
|
||
#include "base/basictypes.h" | ||
#include "base/memory/scoped_ptr.h" | ||
#include "base/string_piece.h" | ||
#include "build/build_config.h" | ||
#include "crypto/crypto_export.h" | ||
|
||
namespace crypto { | ||
|
||
// HKDF implements the key derivation function specified in RFC 5869 (using | ||
// SHA-256) and outputs key material, as needed by QUIC. | ||
// See https://tools.ietf.org/html/rfc5869 for details. | ||
class CRYPTO_EXPORT HKDF { | ||
public: | ||
// |secret|: The input shared secret (or, from RFC 5869, the IKM). | ||
// |salt|: an (optional) public salt / non-secret random value. While | ||
// optional, callers are strongly recommended to provide a salt. There is no | ||
// added security value in making this larger than the SHA-256 block size of | ||
// 64 bytes. | ||
// |info|: an (optional) label to distinguish different uses of HKDF. It is | ||
// optional context and application specific information (can be a zero-length | ||
// string). | ||
// |key_bytes_to_generate|: the number of bytes of key material to generate. | ||
// |iv_bytes_to_generate|: the number of bytes of IV to generate. | ||
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); | ||
virtual ~HKDF(); | ||
|
||
base::StringPiece client_write_key() const { | ||
return client_write_key_; | ||
} | ||
base::StringPiece client_write_iv() const { | ||
return client_write_iv_; | ||
} | ||
base::StringPiece server_write_key() const { | ||
return server_write_key_; | ||
} | ||
base::StringPiece server_write_iv() const { | ||
return server_write_iv_; | ||
} | ||
|
||
private: | ||
std::vector<uint8> output_; | ||
|
||
base::StringPiece client_write_key_; | ||
base::StringPiece server_write_key_; | ||
base::StringPiece client_write_iv_; | ||
base::StringPiece server_write_iv_; | ||
}; | ||
|
||
} // namespace crypto | ||
|
||
#endif // CRYPTO_HKDF_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright (c) 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "crypto/hkdf.h" | ||
|
||
#include <string> | ||
|
||
#include "base/strings/string_number_conversions.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
using crypto::HKDF; | ||
|
||
namespace test { | ||
namespace { | ||
|
||
struct HKDFTest { | ||
const char* key_hex; | ||
const char* salt_hex; | ||
const char* info_hex; | ||
const char* output_hex; | ||
}; | ||
|
||
// These test cases are taken from | ||
// https://tools.ietf.org/html/rfc5869#appendix-A. | ||
static const HKDFTest kHKDFTests[] = {{ | ||
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", | ||
"000102030405060708090a0b0c", | ||
"f0f1f2f3f4f5f6f7f8f9", | ||
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5" | ||
"b887185865", | ||
}, { | ||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324" | ||
"25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849" | ||
"4a4b4c4d4e4f", | ||
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384" | ||
"85868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9" | ||
"aaabacadaeaf", | ||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4" | ||
"d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9" | ||
"fafbfcfdfeff", | ||
"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99ca" | ||
"c7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c" | ||
"01d5c1f3434f1d87", | ||
}, { | ||
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", | ||
"", | ||
"", | ||
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395fa" | ||
"a4b61a96c8", | ||
}, | ||
}; | ||
|
||
TEST(HKDFTest, HKDF) { | ||
for (size_t i = 0; i < arraysize(kHKDFTests); i++) { | ||
const HKDFTest& test(kHKDFTests[i]); | ||
SCOPED_TRACE(i); | ||
|
||
std::vector<uint8> data; | ||
ASSERT_TRUE(base::HexStringToBytes(test.key_hex, &data)); | ||
const std::string key(reinterpret_cast<char*>(&data[0]), data.size()); | ||
|
||
data.clear(); | ||
// |salt_hex| is optional and may be empty. | ||
std::string salt(test.salt_hex); | ||
if (!salt.empty()) { | ||
ASSERT_TRUE(base::HexStringToBytes(salt, &data)); | ||
salt.assign(reinterpret_cast<char*>(&data[0]), data.size()); | ||
} | ||
|
||
data.clear(); | ||
// |info_hex| is optional and may be empty. | ||
std::string info(test.info_hex); | ||
if (!info.empty()) { | ||
ASSERT_TRUE(base::HexStringToBytes(info, &data)); | ||
info.assign(reinterpret_cast<char*>(&data[0]), data.size()); | ||
} | ||
|
||
data.clear(); | ||
ASSERT_TRUE(base::HexStringToBytes(test.output_hex, &data)); | ||
const std::string expected(reinterpret_cast<char*>(&data[0]), data.size()); | ||
|
||
// We set the key_length to the length of the expected output and then take | ||
// the result from the first key, which is the client write key. | ||
HKDF hkdf(key, salt, info, expected.size(), 0); | ||
|
||
ASSERT_EQ(expected.size(), hkdf.client_write_key().size()); | ||
EXPECT_EQ(0, memcmp(expected.data(), hkdf.client_write_key().data(), | ||
expected.size())); | ||
} | ||
} | ||
|
||
} // namespace | ||
} // namespace test |