blob: 1aa50d8c8c15122d5f086671f3d19154ac3e76f7 [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 "libhwsec-foundation/crypto/ecdh_hkdf.h"
#include <base/logging.h>
#include <crypto/scoped_openssl_types.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/sha.h>
#include "libhwsec-foundation/crypto/big_num_util.h"
#include "libhwsec-foundation/crypto/elliptic_curve.h"
#include "libhwsec-foundation/crypto/hkdf.h"
namespace hwsec_foundation {
crypto::ScopedEC_POINT ComputeEcdhSharedSecretPoint(
const EllipticCurve& ec,
const EC_POINT& others_pub_key,
const BIGNUM& own_priv_key) {
ScopedBN_CTX context = CreateBigNumContext();
if (!context) {
LOG(ERROR) << "Failed to allocate BN_CTX structure";
return nullptr;
}
crypto::ScopedEC_POINT shared_secret_point =
ec.Multiply(others_pub_key, own_priv_key, context.get());
if (!shared_secret_point) {
LOG(ERROR) << "Failed to perform scalar multiplication";
return nullptr;
}
return shared_secret_point;
}
bool ComputeEcdhSharedSecret(const EllipticCurve& ec,
const EC_POINT& shared_secret_point,
brillo::SecureBlob* shared_secret) {
ScopedBN_CTX context = CreateBigNumContext();
if (!context) {
LOG(ERROR) << "Failed to allocate BN_CTX structure";
return false;
}
// Get shared point's affine X coordinate.
crypto::ScopedBIGNUM shared_x = CreateBigNum();
if (!shared_x) {
LOG(ERROR) << "Failed to allocate BIGNUM";
return false;
}
if (!ec.GetAffineCoordinates(shared_secret_point, context.get(),
shared_x.get(),
/*y=*/nullptr)) {
LOG(ERROR) << "Failed to get shared_secret_point x coordinate";
return false;
}
// Convert X coordinate to fixed-size blob.
if (!BigNumToSecureBlob(*shared_x, ec.AffineCoordinateSizeInBytes(),
shared_secret)) {
LOG(ERROR) << "Failed to convert BIGNUM to SecureBlob";
return false;
}
return true;
}
bool ComputeHkdfWithInfoSuffix(const brillo::SecureBlob& hkdf_secret,
const brillo::SecureBlob& hkdf_info_suffix,
const brillo::SecureBlob& public_key,
const brillo::SecureBlob& hkdf_salt,
HkdfHash hkdf_hash,
size_t symmetric_key_len,
brillo::SecureBlob* symmetric_key) {
// Compute HKDF using info = combined public_key and hkdf_info_suffix.
brillo::SecureBlob info =
brillo::SecureBlob::Combine(public_key, hkdf_info_suffix);
return Hkdf(hkdf_hash, hkdf_secret, info, hkdf_salt, symmetric_key_len,
symmetric_key);
}
bool GenerateEcdhHkdfSymmetricKey(const EllipticCurve& ec,
const EC_POINT& shared_secret_point,
const brillo::SecureBlob& source_pub_key,
const brillo::SecureBlob& hkdf_info_suffix,
const brillo::SecureBlob& hkdf_salt,
HkdfHash hkdf_hash,
size_t symmetric_key_len,
brillo::SecureBlob* symmetric_key) {
brillo::SecureBlob shared_secret;
if (!ComputeEcdhSharedSecret(ec, shared_secret_point, &shared_secret)) {
LOG(ERROR) << "Failed to compute shared secret";
return false;
}
// Compute HKDF using info = combined source_pub_key and hkdf_info_suffix.
brillo::SecureBlob info =
brillo::SecureBlob::Combine(source_pub_key, hkdf_info_suffix);
if (!ComputeHkdfWithInfoSuffix(shared_secret, hkdf_info_suffix,
source_pub_key, hkdf_salt, hkdf_hash,
symmetric_key_len, symmetric_key)) {
LOG(ERROR) << "Failed to compute HKDF";
return false;
}
// Dispose shared_secret after used
shared_secret.clear();
return true;
}
} // namespace hwsec_foundation