#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) {
base::StringPiece actual_salt = salt;
char zeros[kSHA256HashLength];
if (actual_salt.empty()) {
memset(zeros, 0, sizeof(zeros));
actual_salt.set(zeros, sizeof(zeros));
}
HMAC prk_hmac(HMAC::SHA256);
bool result = prk_hmac.Init(actual_salt);
DCHECK(result);
uint8 prk[kSHA256HashLength];
DCHECK_EQ(sizeof(prk), prk_hmac.DigestLength());
result = prk_hmac.Sign(secret, prk, sizeof(prk));
DCHECK(result);
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;
scoped_ptr<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.get(), previous.data(), previous.size());
size_t j = previous.size();
memcpy(buf.get() + j, info.data(), info.size());
j += info.size();
buf[j++] = static_cast<char>(i + 1);
result = hmac.Sign(base::StringPiece(buf.get(), 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;
if (key_bytes_to_generate) {
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;
}
if (iv_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);
}
}
HKDF::~HKDF() {
}
}