blob: 73fc25d943737e4711ae7523760728f7518cd085 [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 "cryptohome/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 "cryptohome/crypto/big_num_util.h"
#include "cryptohome/crypto/elliptic_curve.h"
#include "cryptohome/crypto/hkdf.h"
namespace cryptohome {
bool ComputeEcdhSharedSecret(const EllipticCurve& ec,
const brillo::SecureBlob& pub_key,
const brillo::SecureBlob& priv_key,
brillo::SecureBlob* shared_secret) {
ScopedBN_CTX context = CreateBigNumContext();
if (!context) {
LOG(ERROR) << "Failed to allocate BN_CTX structure";
return false;
}
crypto::ScopedEC_POINT pub_point =
ec.SecureBlobToPoint(pub_key, context.get());
if (!pub_point) {
LOG(ERROR) << "Failed to convert SecureBlob to EC_POINT";
return false;
}
crypto::ScopedBIGNUM priv_scalar = SecureBlobToBigNum(priv_key);
if (!priv_scalar) {
LOG(ERROR) << "Failed to convert SecureBlob to BIGNUM";
return false;
}
crypto::ScopedEC_POINT shared_point =
ec.Multiply(*pub_point, *priv_scalar, context.get());
if (!shared_point) {
LOG(ERROR) << "Failed to perform scalar multiplication";
return false;
}
// Get shared point's affine X coordinate.
crypto::ScopedBIGNUM shared_x =
ec.GetAffineCoordinateX(*shared_point, context.get());
if (!shared_x) {
LOG(ERROR) << "Failed to get affine X coordinate";
return false;
}
// Convert X coordinate to fixed-size blob.
if (!BigNumToSecureBlob(*shared_x, ec.FieldElementSizeInBytes(),
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 GenerateEcdhHkdfSenderKey(const EllipticCurve& ec,
const brillo::SecureBlob& recipient_pub_key,
const brillo::SecureBlob& ephemeral_pub_key,
const brillo::SecureBlob& ephemeral_priv_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, recipient_pub_key, ephemeral_priv_key,
&shared_secret)) {
LOG(ERROR) << "Failed to compute shared secret";
return false;
}
if (!ComputeHkdfWithInfoSuffix(shared_secret, hkdf_info_suffix,
ephemeral_pub_key, hkdf_salt, hkdf_hash,
symmetric_key_len, symmetric_key)) {
LOG(ERROR) << "Failed to compute HKDF";
return false;
}
return true;
}
bool GenerateEcdhHkdfRecipientKey(const EllipticCurve& ec,
const brillo::SecureBlob& recipient_priv_key,
const brillo::SecureBlob& ephemeral_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, ephemeral_pub_key, recipient_priv_key,
&shared_secret)) {
LOG(ERROR) << "Failed to compute shared secret";
return false;
}
// Compute HKDF using info = combined ephemeral_pub_key and hkdf_info_suffix.
brillo::SecureBlob info =
brillo::SecureBlob::Combine(ephemeral_pub_key, hkdf_info_suffix);
if (!ComputeHkdfWithInfoSuffix(shared_secret, hkdf_info_suffix,
ephemeral_pub_key, hkdf_salt, hkdf_hash,
symmetric_key_len, symmetric_key)) {
LOG(ERROR) << "Failed to compute HKDF";
return false;
}
return true;
}
} // namespace cryptohome