Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In EC keys store the data as EC_Scalar / EC_AffinePoint #4203

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions src/lib/prov/pkcs11/p11_ecc_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,21 @@
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)

#include <botan/ber_dec.h>
#include <botan/internal/ec_key_data.h>
#include <botan/internal/workfactor.h>

namespace Botan::PKCS11 {

namespace {

/// Converts a DER-encoded ANSI X9.62 ECPoint to EC_Point
EC_Point decode_public_point(const secure_vector<uint8_t>& ec_point_data, const EC_Group& group) {
secure_vector<uint8_t> ec_point;
EC_AffinePoint decode_public_point(const EC_Group& group, std::span<const uint8_t> ec_point_data) {
std::vector<uint8_t> ec_point;
BER_Decoder(ec_point_data).decode(ec_point, ASN1_Type::OctetString);
return group.OS2ECP(ec_point);
// Throws if invalid
return EC_AffinePoint(group, ec_point);
}

} // namespace

EC_PublicKeyGenerationProperties::EC_PublicKeyGenerationProperties(const std::vector<uint8_t>& ec_params) :
Expand All @@ -38,20 +43,19 @@ EC_PublicKeyImportProperties::EC_PublicKeyImportProperties(const std::vector<uin
}

PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, ObjectHandle handle) : Object(session, handle) {
secure_vector<uint8_t> ec_parameters = get_attribute_value(AttributeType::EcParams);
m_domain_params = EC_Group(unlock(ec_parameters));
m_public_key = decode_public_point(get_attribute_value(AttributeType::EcPoint), m_domain_params);
m_domain_encoding = EC_Group_Encoding::NamedCurve;
auto ec_parameters = get_attribute_value(AttributeType::EcParams);
auto pt_bytes = get_attribute_value(AttributeType::EcPoint);

EC_Group group(ec_parameters);
auto pt = decode_public_point(group, pt_bytes);
m_public_key = std::make_shared<EC_PublicKey_Data>(std::move(group), std::move(pt));
}

PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) :
Object(session, props) {
m_domain_params = EC_Group(props.ec_params());

secure_vector<uint8_t> ec_point;
BER_Decoder(props.ec_point()).decode(ec_point, ASN1_Type::OctetString);
m_public_key = m_domain_params.OS2ECP(ec_point);
m_domain_encoding = EC_Group_Encoding::NamedCurve;
EC_Group group(props.ec_params());
auto pt = decode_public_point(group, props.ec_point());
m_public_key = std::make_shared<EC_PublicKey_Data>(std::move(group), std::move(pt));
}

EC_PrivateKeyImportProperties::EC_PrivateKeyImportProperties(const std::vector<uint8_t>& ec_params,
Expand All @@ -61,8 +65,7 @@ EC_PrivateKeyImportProperties::EC_PrivateKeyImportProperties(const std::vector<u
add_binary(AttributeType::Value, m_value.serialize());
}

PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle) :
Object(session, handle), m_domain_params(), m_public_key() {
PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle) : Object(session, handle) {
secure_vector<uint8_t> ec_parameters = get_attribute_value(AttributeType::EcParams);
m_domain_params = EC_Group(unlock(ec_parameters));
}
Expand Down Expand Up @@ -96,9 +99,10 @@ PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session,
&priv_key_handle);

this->reset_handle(priv_key_handle);

Object public_key(session, pub_key_handle);
m_public_key = decode_public_point(public_key.get_attribute_value(AttributeType::EcPoint), m_domain_params);

auto pt_bytes = public_key.get_attribute_value(AttributeType::EcPoint);
m_public_key = decode_public_point(m_domain_params, pt_bytes).to_legacy_point();
}

size_t PKCS11_EC_PrivateKey::key_length() const {
Expand Down
9 changes: 7 additions & 2 deletions src/lib/pubkey/ec_group/ec_apoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ class EC_AffinePoint_Data;

class BOTAN_UNSTABLE_API EC_AffinePoint final {
public:
/// Point deserialization. Throws if wrong length or not a valid point
///
/// This accepts SEC1 compressed or uncompressed formats
EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes);

/// Point deserialization. Returns nullopt if wrong length or not a valid point
///
/// This accepts SEC1 compressed or uncompressed formats
static std::optional<EC_AffinePoint> deserialize(const EC_Group& group, std::span<const uint8_t> bytes);

/// Multiply by the group generator returning a complete point
Expand Down Expand Up @@ -133,8 +140,6 @@ class BOTAN_UNSTABLE_API EC_AffinePoint final {
EC_AffinePoint& operator=(const EC_AffinePoint& other);
EC_AffinePoint& operator=(EC_AffinePoint&& other) noexcept;

EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes);

/**
* Deprecated conversion
*/
Expand Down
3 changes: 0 additions & 3 deletions src/lib/pubkey/ec_group/ec_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,9 +745,6 @@ bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
return true;
}

EC_Group::Mul2Table::Mul2Table(const EC_Group& group, const EC_Point& h) :
EC_Group::Mul2Table(EC_AffinePoint(group, h)) {}

EC_Group::Mul2Table::Mul2Table(const EC_AffinePoint& h) : m_tbl(h._group()->make_mul2_table(h._inner())) {}

EC_Group::Mul2Table::~Mul2Table() = default;
Expand Down
7 changes: 0 additions & 7 deletions src/lib/pubkey/ec_group/ec_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,6 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final {
/// Table for computing g*x + h*y
class Mul2Table final {
public:
/**
* Internal transition function
*
* @warning this will be removed in 3.6.0, NOT COVERED BY SEMVER
*/
Mul2Table(const EC_Group& group, const EC_Point& h);

/**
* Create a table for computing g*x + h*y
*/
Expand Down
13 changes: 13 additions & 0 deletions src/lib/pubkey/ec_group/ec_scalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ EC_Scalar EC_Scalar::from_bigint(const EC_Group& group, const BigInt& bn) {
return EC_Scalar(group._data()->scalar_from_bigint(bn));
}

BigInt EC_Scalar::to_bigint() const {
secure_vector<uint8_t> bytes(m_scalar->bytes());
m_scalar->serialize_to(bytes);
return BigInt::from_bytes(bytes);
}

EC_Scalar EC_Scalar::gk_x_mod_order(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) {
const auto& group = scalar._inner().group();
return EC_Scalar(group->gk_x_mod_order(scalar.inner(), rng, ws));
Expand Down Expand Up @@ -106,6 +112,13 @@ std::optional<EC_Scalar> EC_Scalar::deserialize(const EC_Group& group, std::span
}
}

EC_Scalar::EC_Scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
m_scalar = group._data()->scalar_deserialize(bytes);
if(!m_scalar) {
throw Decoding_Error("EC_Scalar::from_bytes is not a valid scalar value");
}
}

bool EC_Scalar::is_zero() const {
return inner().is_zero();
}
Expand Down
13 changes: 13 additions & 0 deletions src/lib/pubkey/ec_group/ec_scalar.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ class BOTAN_UNSTABLE_API EC_Scalar final {
*/
static EC_Scalar from_bytes_mod_order(const EC_Group& group, std::span<const uint8_t> bytes);

/**
* Convert a bytestring to an EC_Scalar
*
* This is similar to deserialize but instead of returning nullopt if the input
* is invalid, it will throw an exception.
*/
EC_Scalar(const EC_Group& group, std::span<const uint8_t> bytes);

/**
* Deserialize a pair of scalars
*
Expand Down Expand Up @@ -180,6 +188,11 @@ class BOTAN_UNSTABLE_API EC_Scalar final {
*/
bool is_eq(const EC_Scalar& x) const;

/**
* Convert *this to a BigInt
*/
BigInt to_bigint() const;

friend EC_Scalar operator+(const EC_Scalar& x, const EC_Scalar& y) { return x.add(y); }

friend EC_Scalar operator-(const EC_Scalar& x, const EC_Scalar& y) { return x.sub(y); }
Expand Down
51 changes: 51 additions & 0 deletions src/lib/pubkey/ecc_key/ec_key_data.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* (C) 2024 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/ec_key_data.h>

#include <botan/rng.h>

namespace Botan {

EC_PublicKey_Data::EC_PublicKey_Data(EC_Group group, std::span<const uint8_t> bytes) :
m_group(std::move(group)), m_point(m_group, bytes), m_legacy_point(m_point.to_legacy_point()) {}

EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, RandomNumberGenerator& rng) :
m_group(std::move(group)), m_scalar(EC_Scalar::random(m_group, rng)), m_legacy_x(m_scalar.to_bigint()) {}

EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, const BigInt& x) :
m_group(std::move(group)), m_scalar(EC_Scalar::from_bigint(m_group, x)), m_legacy_x(m_scalar.to_bigint()) {}

EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, EC_Scalar x) :
m_group(std::move(group)), m_scalar(std::move(x)), m_legacy_x(m_scalar.to_bigint()) {}

EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, std::span<const uint8_t> bytes) :
m_group(std::move(group)), m_scalar(m_group, bytes), m_legacy_x(m_scalar.to_bigint()) {}

std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(RandomNumberGenerator& rng,
bool with_modular_inverse) const {
auto public_point = [&] {
std::vector<BigInt> ws;
if(with_modular_inverse) {
return EC_AffinePoint::g_mul(m_scalar.invert(), rng, ws);
} else {
return EC_AffinePoint::g_mul(m_scalar, rng, ws);
}
};

return std::make_shared<EC_PublicKey_Data>(m_group, public_point());
}

std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(bool with_modular_inverse) const {
Null_RNG null_rng;
return this->public_key(null_rng, with_modular_inverse);
}

void EC_PrivateKey_Data::serialize_to(std::span<uint8_t> output) const {
m_scalar.serialize_to(output);
}

} // namespace Botan
78 changes: 78 additions & 0 deletions src/lib/pubkey/ecc_key/ec_key_data.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* (C) 2024 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_EC_KEY_DATA_H_
#define BOTAN_EC_KEY_DATA_H_

#include <botan/ec_apoint.h>
#include <botan/ec_group.h>
#include <botan/ec_scalar.h>

#include <botan/bigint.h>
#include <botan/ec_point.h>

namespace Botan {

class RandomNumberGenerator;

class EC_PublicKey_Data final {
public:
EC_PublicKey_Data(EC_Group group, EC_AffinePoint pt) :
m_group(std::move(group)), m_point(std::move(pt)), m_legacy_point(m_point.to_legacy_point()) {}

EC_PublicKey_Data(EC_Group group, std::span<const uint8_t> bytes);

const EC_Group& group() const { return m_group; }

const EC_AffinePoint& public_key() const { return m_point; }

const EC_Point& legacy_point() const { return m_legacy_point; }

private:
EC_Group m_group;
EC_AffinePoint m_point;
EC_Point m_legacy_point;
};

class EC_PrivateKey_Data final {
public:
EC_PrivateKey_Data(EC_Group group, RandomNumberGenerator& rng);

EC_PrivateKey_Data(EC_Group group, const BigInt& x);

EC_PrivateKey_Data(EC_Group group, EC_Scalar x);

EC_PrivateKey_Data(EC_Group group, std::span<const uint8_t> bytes);

std::shared_ptr<EC_PublicKey_Data> public_key(RandomNumberGenerator& rng, bool with_modular_inverse) const;

std::shared_ptr<EC_PublicKey_Data> public_key(bool with_modular_inverse) const;

void serialize_to(std::span<uint8_t> output) const;

template <typename T>
T serialize() const {
T bytes(this->group().get_order_bytes());
this->serialize_to(bytes);
return bytes;
}

const EC_Group& group() const { return m_group; }

const EC_Scalar& private_key() const { return m_scalar; }

const BigInt& legacy_bigint() const { return m_legacy_x; }

private:
EC_Group m_group;

EC_Scalar m_scalar;
BigInt m_legacy_x;
};

} // namespace Botan

#endif
Loading
Loading