// Copyright 2017 The Fuchsia 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 #include #include #include #include #include #include #include #include #include // See note in //zircon/third_party/ulib/uboringssl/rules.mk #define BORINGSSL_NO_CXX #include #include #include "error.h" #define ZXDEBUG 0 namespace crypto { namespace { const uint16_t kAllFlags = HKDF::ALLOW_WEAK_KEY; } // Public methods HKDF::HKDF() : digest_(digest::kUninitialized) {} HKDF::~HKDF() {} zx_status_t HKDF::Init(digest::Algorithm digest, const Secret& key, const Bytes& salt, uint16_t flags) { zx_status_t rc; if ((flags & (~kAllFlags)) != 0) { xprintf("invalid flags: %04x\n", flags); return ZX_ERR_INVALID_ARGS; } uintptr_t ptr; if ((rc = digest::GetDigest(digest, &ptr)) != ZX_OK) { return rc; } digest_ = digest; const EVP_MD* md = reinterpret_cast(ptr); // Reserve space for the pseudo-random key. uint8_t *prk; size_t prk_len = EVP_MD_size(md); if ((rc = prk_.Allocate(prk_len, &prk)) != ZX_OK) { return rc; } // Recommended minimum length for the key is the digest output length (RFC 2104, section 2). if ((flags & ALLOW_WEAK_KEY) == 0 && key.len() < prk_len) { xprintf("weak parameter(s): key_len=%zu", key.len()); return ZX_ERR_INVALID_ARGS; } // Extract the PRK used to generate other keys. if (HKDF_extract(prk, &prk_len, md, key.get(), key.len(), salt.get(), salt.len()) < 0) { xprintf_crypto_errors(&rc); return rc; } ZX_DEBUG_ASSERT(prk_len == prk_.len()); return ZX_OK; } zx_status_t HKDF::Derive(const char* label, size_t len, Bytes* out) { zx_status_t rc; if ((rc = out->Resize(len)) != ZX_OK || (rc = Derive(label, out->get(), len)) != ZX_OK) { return rc; } return ZX_OK; } zx_status_t HKDF::Derive(const char* label, size_t len, Secret* out) { zx_status_t rc; uint8_t *buf; if ((rc = out->Allocate(len, &buf)) != ZX_OK || (rc = Derive(label, buf, len)) != ZX_OK) { return rc; } return ZX_OK; } zx_status_t HKDF::Derive(const char* label, uint8_t* out, size_t out_len) { zx_status_t rc; if (!out || out_len == 0) { xprintf("bad parameter(s): out=%p, out_len=%zu\n", out, out_len); return ZX_ERR_INVALID_ARGS; } uintptr_t ptr; if ((rc = digest::GetDigest(digest_, &ptr)) != ZX_OK) { return rc; } const EVP_MD* md = reinterpret_cast(ptr); // Maybe the platform is weird... static_assert(sizeof(uint8_t) == sizeof(char), "can't convert char to uint8_t"); const uint8_t* info = reinterpret_cast(label); size_t info_len = label ? strlen(label) : 0; // Generate the key if (HKDF_expand(out, out_len, md, prk_.get(), prk_.len(), info, info_len) < 0) { xprintf_crypto_errors(&rc); return rc; } return ZX_OK; } } // namespace crypto