Skip to content

Commit

Permalink
Merge pull request #3985 from Rohde-Schwarz/feature/raw_public_key_bits
Browse files Browse the repository at this point in the history
  • Loading branch information
reneme committed May 23, 2024
2 parents d6b946d + db3cbe6 commit 2d52a43
Show file tree
Hide file tree
Showing 66 changed files with 382 additions and 94 deletions.
21 changes: 21 additions & 0 deletions doc/api_ref/pubkey.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ removed in a future major release.

.. cpp:function:: std::vector<uint8_t> public_key_bits() const = 0;

Returns a binary representation of the public key. Typically this is a
BER encoded structure that includes metadata like the algorithm and
parameter set used to generate the key.

Note that pre-standard post-quantum algorithms of the NIST competition
(e.g. Kyber, Dilithium, FrodoKEM, etc) do not have a standardized BER
encoding, yet. For the time being, the raw public key bits are returned
for these algorithms. That might change as the standards evolve.

.. cpp:function:: std::vector<uint8_t> raw_public_key_bits() const = 0;

Returns a binary representation of the public key's canonical structure.
Typically, this does not include any metadata like an algorithm identifier
or parameter set. Note that some schemes (e.g. RSA) do not know such "raw"
canonical structure and therefore throw `Not_Implemented`.
For key agreement algorithms, this is the canonical public value of the
scheme.

Decoding the resulting raw bytes typically requires knowledge of the
algorithm and parameters used to generate the key.

.. cpp:function:: std::vector<uint8_t> subject_public_key() const;

Return the X.509 SubjectPublicKeyInfo encoding of this key
Expand Down
19 changes: 14 additions & 5 deletions src/examples/hybrid_key_encapsulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ class Hybrid_PublicKey : public virtual Botan::Public_Key {
throw Botan::Not_Implemented("Hybrid-KEM does not have an algorithm identifier");
}

/**
* In an actual implementation, this may return a serialized
* representation of the public keys. For instance, a mere concatenation
* of the two public keys.
*/
std::vector<uint8_t> raw_public_key_bits() const override {
throw Botan::Not_Implemented("Raw key serialization is not supported");
}

/**
* In an actual implementation, this may return a serialized
* representation of the public keys. For instance, using some ASN.1
Expand Down Expand Up @@ -161,7 +170,7 @@ class Hybrid_Encryption_Operation : public Botan::PK_Ops::KEM_Encryption {
* key (ephemeral key pair) and the length of the KEM's encapsulated key.
*/
size_t encapsulated_key_length() const override {
return m_hybrid_pk.kex_public_key().public_key_bits().size() + m_kem_encryptor.encapsulated_key_length();
return m_hybrid_pk.kex_public_key().raw_public_key_bits().size() + m_kem_encryptor.encapsulated_key_length();
}

/**
Expand Down Expand Up @@ -212,8 +221,8 @@ class Hybrid_Encryption_Operation : public Botan::PK_Ops::KEM_Encryption {
// TODO: kex.derive_key() should allow a std::span<>-based out param,
// which would save a copy in this case. (See GH #3318)
const auto kex_shared_key =
kex.derive_key(0 /* no KDF */, m_hybrid_pk.kex_public_key().public_key_bits()).bits_of();
const auto kex_encapsed_key = ephemeral_keypair->public_key_bits();
kex.derive_key(0 /* no KDF */, m_hybrid_pk.kex_public_key().raw_public_key_bits()).bits_of();
const auto kex_encapsed_key = ephemeral_keypair->raw_public_key_bits();

// 3. KEX: Encapsulate a shared secret using the KEM's public key,
// yielding a shared secret and its encapsulation.
Expand Down Expand Up @@ -266,7 +275,7 @@ class Hybrid_Decryption_Operation : public Botan::PK_Ops::KEM_Decryption {
* key (ephemeral key pair) and the length of the KEM's encapsulated key.
*/
size_t encapsulated_key_length() const override {
return m_hybrid_sk.kex_public_key().public_key_bits().size() + m_kem_decryptor.encapsulated_key_length();
return m_hybrid_sk.kex_public_key().raw_public_key_bits().size() + m_kem_decryptor.encapsulated_key_length();
}

/**
Expand Down Expand Up @@ -298,7 +307,7 @@ class Hybrid_Decryption_Operation : public Botan::PK_Ops::KEM_Decryption {

// 1. Hybrid: Extract the ephemeral public key and the encapsulation.
const auto kex_encapsed_key =
encapsulated_key.subspan(0, m_hybrid_sk.kex_public_key().public_key_bits().size());
encapsulated_key.subspan(0, m_hybrid_sk.kex_public_key().raw_public_key_bits().size());
const auto kem_encapsed_key = encapsulated_key.subspan(kex_encapsed_key.size());

// 2. KEX: Agree on a shared secret using the KEX's private key and the
Expand Down
4 changes: 4 additions & 0 deletions src/lib/prov/pkcs11/p11_ecc_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ size_t PKCS11_EC_PrivateKey::key_length() const {
return m_domain_params.get_order().bits();
}

std::vector<uint8_t> PKCS11_EC_PrivateKey::raw_public_key_bits() const {
return public_point().encode(EC_Point_Format::Compressed);
}

std::vector<uint8_t> PKCS11_EC_PrivateKey::public_key_bits() const {
return public_point().encode(EC_Point_Format::Compressed);
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/prov/pkcs11/p11_ecc_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ class BOTAN_PUBLIC_API(2, 0) PKCS11_EC_PrivateKey : public virtual Private_Key,

// Private_Key methods

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

std::size_t key_length() const override;
Expand Down
4 changes: 4 additions & 0 deletions src/lib/prov/tpm/tpm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ std::vector<uint8_t> TPM_PrivateKey::public_key_bits() const {
return bits;
}

std::vector<uint8_t> TPM_PrivateKey::raw_public_key_bits() const {
throw TPM_Error("Raw public key export not supported for RSA TPM keys");
}

secure_vector<uint8_t> TPM_PrivateKey::private_key_bits() const {
throw TPM_Error("Private key export not supported for TPM keys");
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/prov/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class BOTAN_PUBLIC_API(2, 0) TPM_PrivateKey final : public Private_Key {

std::vector<uint8_t> public_key_bits() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

secure_vector<uint8_t> private_key_bits() const override;

bool check_key(RandomNumberGenerator& rng, bool) const override;
Expand Down
6 changes: 5 additions & 1 deletion src/lib/pubkey/curve448/ed448/ed448.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,14 @@ Ed448_PublicKey::Ed448_PublicKey(std::span<const uint8_t> key_bits) {
copy_mem(m_public, key_bits.first<ED448_LEN>());
}

std::vector<uint8_t> Ed448_PublicKey::public_key_bits() const {
std::vector<uint8_t> Ed448_PublicKey::raw_public_key_bits() const {
return {m_public.begin(), m_public.end()};
}

std::vector<uint8_t> Ed448_PublicKey::public_key_bits() const {
return raw_public_key_bits();
}

std::unique_ptr<Private_Key> Ed448_PublicKey::generate_another(RandomNumberGenerator& rng) const {
return std::make_unique<Ed448_PrivateKey>(rng);
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/curve448/ed448/ed448.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BOTAN_PUBLIC_API(3, 4) Ed448_PublicKey : public virtual Public_Key {

AlgorithmIdentifier algorithm_identifier() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

std::unique_ptr<Private_Key> generate_another(RandomNumberGenerator& rng) const final;
Expand Down
4 changes: 4 additions & 0 deletions src/lib/pubkey/curve448/x448/x448.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ bool X448_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/)
return true; // no tests possible?
}

std::vector<uint8_t> X448_PublicKey::raw_public_key_bits() const {
return public_value();
}

std::vector<uint8_t> X448_PublicKey::public_key_bits() const {
return public_value();
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/curve448/x448/x448.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class BOTAN_PUBLIC_API(3, 4) X448_PublicKey : public virtual Public_Key {

std::vector<uint8_t> public_value() const { return {m_public.begin(), m_public.end()}; }

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

bool supports_operation(PublicKeyOperation op) const override { return (op == PublicKeyOperation::KeyAgreement); }
Expand Down
4 changes: 4 additions & 0 deletions src/lib/pubkey/dh/dh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ AlgorithmIdentifier DH_PublicKey::algorithm_identifier() const {
return AlgorithmIdentifier(object_identifier(), m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
}

std::vector<uint8_t> DH_PublicKey::raw_public_key_bits() const {
return public_value();
}

std::vector<uint8_t> DH_PublicKey::public_key_bits() const {
return m_public_key->DER_encode();
}
Expand Down
3 changes: 3 additions & 0 deletions src/lib/pubkey/dh/dh.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class BOTAN_PUBLIC_API(2, 0) DH_PublicKey : public virtual Public_Key {
DH_PublicKey(const DL_Group& group, const BigInt& y);

AlgorithmIdentifier algorithm_identifier() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator& rng, bool strong) const override;
Expand Down
8 changes: 7 additions & 1 deletion src/lib/pubkey/dilithium/dilithium_common/dilithium.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,10 +532,16 @@ size_t Dilithium_PublicKey::estimated_strength() const {
return m_public->mode().nist_security_strength();
}

std::vector<uint8_t> Dilithium_PublicKey::public_key_bits() const {
std::vector<uint8_t> Dilithium_PublicKey::raw_public_key_bits() const {
return m_public->raw_pk();
}

std::vector<uint8_t> Dilithium_PublicKey::public_key_bits() const {
// Currently, there isn't a finalized definition of an ASN.1 structure for
// Dilithium aka ML-DSA public keys. Therefore, we return the raw public key bits.
return raw_public_key_bits();
}

bool Dilithium_PublicKey::check_key(RandomNumberGenerator&, bool) const {
return true; // ???
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/dilithium/dilithium_common/dilithium.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class BOTAN_PUBLIC_API(3, 0) Dilithium_PublicKey : public virtual Public_Key {

size_t estimated_strength() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator&, bool) const override;
Expand Down
4 changes: 4 additions & 0 deletions src/lib/pubkey/dsa/dsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ AlgorithmIdentifier DSA_PublicKey::algorithm_identifier() const {
return AlgorithmIdentifier(object_identifier(), m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_57));
}

std::vector<uint8_t> DSA_PublicKey::raw_public_key_bits() const {
return m_public_key->public_key_as_bytes();
}

std::vector<uint8_t> DSA_PublicKey::public_key_bits() const {
return m_public_key->DER_encode();
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/dsa/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class BOTAN_PUBLIC_API(2, 0) DSA_PublicKey : public virtual Public_Key {
size_t message_part_size() const override;

AlgorithmIdentifier algorithm_identifier() const override;

std::vector<uint8_t> raw_public_key_bits() const override;
std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator& rng, bool strong) const override;
Expand Down
6 changes: 5 additions & 1 deletion src/lib/pubkey/ecc_key/ecc_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,14 @@ AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const {
return AlgorithmIdentifier(object_identifier(), DER_domain());
}

std::vector<uint8_t> EC_PublicKey::public_key_bits() const {
std::vector<uint8_t> EC_PublicKey::raw_public_key_bits() const {
return public_point().encode(point_encoding());
}

std::vector<uint8_t> EC_PublicKey::public_key_bits() const {
return raw_public_key_bits();
}

void EC_PublicKey::set_point_encoding(EC_Point_Format enc) {
if(enc != EC_Point_Format::Compressed && enc != EC_Point_Format::Uncompressed && enc != EC_Point_Format::Hybrid) {
throw Invalid_Argument("Invalid point encoding for EC_PublicKey");
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/ecc_key/ecc_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class BOTAN_PUBLIC_API(2, 0) EC_PublicKey : public virtual Public_Key {

AlgorithmIdentifier algorithm_identifier() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator& rng, bool strong) const override;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/ed25519/ed25519.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class BOTAN_PUBLIC_API(2, 2) Ed25519_PublicKey : public virtual Public_Key {

AlgorithmIdentifier algorithm_identifier() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

std::unique_ptr<Private_Key> generate_another(RandomNumberGenerator& rng) const final;
Expand Down
6 changes: 5 additions & 1 deletion src/lib/pubkey/ed25519/ed25519_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,14 @@ Ed25519_PublicKey::Ed25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std:
}
}

std::vector<uint8_t> Ed25519_PublicKey::public_key_bits() const {
std::vector<uint8_t> Ed25519_PublicKey::raw_public_key_bits() const {
return m_public;
}

std::vector<uint8_t> Ed25519_PublicKey::public_key_bits() const {
return raw_public_key_bits();
}

std::unique_ptr<Private_Key> Ed25519_PublicKey::generate_another(RandomNumberGenerator& rng) const {
return std::make_unique<Ed25519_PrivateKey>(rng);
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib/pubkey/elgamal/elgamal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ AlgorithmIdentifier ElGamal_PublicKey::algorithm_identifier() const {
return AlgorithmIdentifier(object_identifier(), m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
}

std::vector<uint8_t> ElGamal_PublicKey::raw_public_key_bits() const {
return m_public_key->public_key_as_bytes();
}

std::vector<uint8_t> ElGamal_PublicKey::public_key_bits() const {
return m_public_key->DER_encode();
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/pubkey/elgamal/elgamal.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class BOTAN_PUBLIC_API(2, 0) ElGamal_PublicKey : public virtual Public_Key {
ElGamal_PublicKey(const DL_Group& group, const BigInt& y);

AlgorithmIdentifier algorithm_identifier() const override;
std::vector<uint8_t> raw_public_key_bits() const override;
std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator& rng, bool strong) const override;
Expand Down
8 changes: 7 additions & 1 deletion src/lib/pubkey/frodokem/frodokem_common/frodokem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,16 @@ size_t FrodoKEM_PublicKey::estimated_strength() const {
return m_public->constants().estimated_strength();
}

std::vector<uint8_t> FrodoKEM_PublicKey::public_key_bits() const {
std::vector<uint8_t> FrodoKEM_PublicKey::raw_public_key_bits() const {
return concat<std::vector<uint8_t>>(m_public->seed_a(), m_public->b().pack(m_public->constants()));
}

std::vector<uint8_t> FrodoKEM_PublicKey::public_key_bits() const {
// Currently, there isn't a finalized definition of an ASN.1 structure for
// FrodoKEM public keys. Therefore, we return the raw public key bits.
return raw_public_key_bits();
}

bool FrodoKEM_PublicKey::check_key(RandomNumberGenerator&, bool) const {
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_common/frodokem.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class BOTAN_PUBLIC_API(3, 3) FrodoKEM_PublicKey : public virtual Public_Key {

size_t estimated_strength() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator&, bool) const override;
Expand Down
8 changes: 7 additions & 1 deletion src/lib/pubkey/hss_lms/hss_lms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,16 @@ bool HSS_LMS_PublicKey::check_key(RandomNumberGenerator&, bool) const {
return true;
}

std::vector<uint8_t> HSS_LMS_PublicKey::public_key_bits() const {
std::vector<uint8_t> HSS_LMS_PublicKey::raw_public_key_bits() const {
return m_public->to_bytes();
}

std::vector<uint8_t> HSS_LMS_PublicKey::public_key_bits() const {
// The raw encoding of HSS/LMS public keys always contains the necessary
// algorithm information.
return raw_public_key_bits();
}

class HSS_LMS_Verification_Operation final : public PK_Ops::Verification {
public:
HSS_LMS_Verification_Operation(std::shared_ptr<HSS_LMS_PublicKeyInternal> pub_key) :
Expand Down
1 change: 1 addition & 0 deletions src/lib/pubkey/hss_lms/hss_lms.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class BOTAN_PUBLIC_API(3, 5) HSS_LMS_PublicKey : public virtual Public_Key {
AlgorithmIdentifier algorithm_identifier() const override;
OID object_identifier() const override;
bool check_key(RandomNumberGenerator& rng, bool strong) const override;
std::vector<uint8_t> raw_public_key_bits() const override;
std::vector<uint8_t> public_key_bits() const override;

std::unique_ptr<PK_Ops::Verification> create_verification_op(std::string_view params,
Expand Down
8 changes: 7 additions & 1 deletion src/lib/pubkey/kyber/kyber_common/kyber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,16 @@ Kyber_PublicKey::Kyber_PublicKey(std::span<const uint8_t> pub_key, KyberMode m)
Kyber_PublicKey::Kyber_PublicKey(const Kyber_PublicKey& other) :
m_public(std::make_shared<Kyber_PublicKeyInternal>(*other.m_public)) {}

std::vector<uint8_t> Kyber_PublicKey::public_key_bits() const {
std::vector<uint8_t> Kyber_PublicKey::raw_public_key_bits() const {
return m_public->public_key_bits_raw().get();
}

std::vector<uint8_t> Kyber_PublicKey::public_key_bits() const {
// Currently, there isn't a finalized definition of an ASN.1 structure for
// Kyber aka ML-KEM public keys. Therefore, we return the raw public key bits.
return raw_public_key_bits();
}

size_t Kyber_PublicKey::key_length() const {
// TODO: this should report 512, 768, 1024
return m_public->mode().public_key_byte_length();
Expand Down
2 changes: 2 additions & 0 deletions src/lib/pubkey/kyber/kyber_common/kyber.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class BOTAN_PUBLIC_API(3, 0) Kyber_PublicKey : public virtual Public_Key {

size_t estimated_strength() const override;

std::vector<uint8_t> raw_public_key_bits() const override;

std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator&, bool) const override;
Expand Down
1 change: 1 addition & 0 deletions src/lib/pubkey/mce/mceliece.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class BOTAN_PUBLIC_API(2, 0) McEliece_PublicKey : public virtual Public_Key {
size_t key_length() const override;
size_t estimated_strength() const override;

std::vector<uint8_t> raw_public_key_bits() const override;
std::vector<uint8_t> public_key_bits() const override;

bool check_key(RandomNumberGenerator&, bool) const override { return true; }
Expand Down
Loading

0 comments on commit 2d52a43

Please sign in to comment.