Source code

Revision control

Copy as Markdown

Other Tools

/*
* Ed448 Signature Algorithm (RFC 8032)
* (C) 2024 Jack Lloyd
* 2024 Fabian Albert - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/ed448.h>
#include <botan/ber_dec.h>
#include <botan/der_enc.h>
#include <botan/hash.h>
#include <botan/rng.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/ed448_internal.h>
#include <botan/internal/pk_ops_impl.h>
#include <utility>
namespace Botan {
AlgorithmIdentifier Ed448_PublicKey::algorithm_identifier() const {
return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM);
}
bool Ed448_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
try {
Ed448Point::decode(m_public);
} catch(Decoding_Error&) {
return false;
}
return true;
}
Ed448_PublicKey::Ed448_PublicKey(const AlgorithmIdentifier& /* unused */, std::span<const uint8_t> key_bits) :
Ed448_PublicKey(key_bits) {}
Ed448_PublicKey::Ed448_PublicKey(std::span<const uint8_t> key_bits) {
if(key_bits.size() != ED448_LEN) {
throw Decoding_Error("Invalid length for Ed448 public key");
}
copy_mem(m_public, key_bits.first<ED448_LEN>());
}
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);
}
Ed448_PrivateKey::Ed448_PrivateKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
secure_vector<uint8_t> bits;
BER_Decoder(key_bits).decode(bits, ASN1_Type::OctetString).verify_end();
if(bits.size() != ED448_LEN) {
throw Decoding_Error("Invalid size for Ed448 private key");
}
m_private = std::move(bits);
m_public = create_pk_from_sk(std::span(m_private).first<ED448_LEN>());
}
Ed448_PrivateKey::Ed448_PrivateKey(RandomNumberGenerator& rng) : Ed448_PrivateKey(rng.random_vec(ED448_LEN)) {}
Ed448_PrivateKey::Ed448_PrivateKey(std::span<const uint8_t> key_bits) {
if(key_bits.size() != ED448_LEN) {
throw Decoding_Error("Invalid size for Ed448 private key");
}
m_private.assign(key_bits.begin(), key_bits.end());
auto scope = CT::scoped_poison(m_private);
m_public = create_pk_from_sk(std::span(m_private).first<ED448_LEN>());
CT::unpoison(m_public);
}
std::unique_ptr<Public_Key> Ed448_PrivateKey::public_key() const {
return std::make_unique<Ed448_PublicKey>(m_public);
}
secure_vector<uint8_t> Ed448_PrivateKey::private_key_bits() const {
BOTAN_ASSERT_NOMSG(m_private.size() == ED448_LEN);
return DER_Encoder().encode(m_private, ASN1_Type::OctetString).get_contents();
}
bool Ed448_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
return true;
}
namespace {
/// Interface to abstract either a pure message or a prehashed message
class Ed448_Message {
public:
virtual void update(std::span<const uint8_t> msg) = 0;
virtual std::vector<uint8_t> get_and_clear() = 0;
Ed448_Message() = default;
virtual ~Ed448_Message() = default;
Ed448_Message(const Ed448_Message&) = delete;
Ed448_Message& operator=(const Ed448_Message&) = delete;
Ed448_Message(Ed448_Message&&) = delete;
Ed448_Message& operator=(Ed448_Message&&) = delete;
};
class Prehashed_Ed448_Message final : public Ed448_Message {
public:
void update(std::span<const uint8_t> msg) override { m_hash->update(msg); }
std::vector<uint8_t> get_and_clear() override { return m_hash->final_stdvec(); }
Prehashed_Ed448_Message(std::string_view hash) : m_hash(HashFunction::create_or_throw(hash)) {}
private:
std::unique_ptr<HashFunction> m_hash;
};
class Pure_Ed448_Message final : public Ed448_Message {
public:
void update(std::span<const uint8_t> msg) override { m_msg.insert(m_msg.end(), msg.begin(), msg.end()); }
std::vector<uint8_t> get_and_clear() override { return std::exchange(m_msg, {}); }
private:
std::vector<uint8_t> m_msg;
};
/**
* Ed448 verifying operation
*/
class Ed448_Verify_Operation final : public PK_Ops::Verification {
public:
explicit Ed448_Verify_Operation(const Ed448_PublicKey& key,
std::optional<std::string> prehash_function = std::nullopt) :
m_prehash_function(std::move(prehash_function)) {
const auto pk_bits = key.public_key_bits();
copy_mem(m_pk, std::span(pk_bits).first<ED448_LEN>());
if(m_prehash_function) {
m_message = std::make_unique<Prehashed_Ed448_Message>(*m_prehash_function);
} else {
m_message = std::make_unique<Pure_Ed448_Message>();
}
}
void update(std::span<const uint8_t> input) override { m_message->update(input); }
bool is_valid_signature(std::span<const uint8_t> sig) override {
const auto msg = m_message->get_and_clear();
try {
return verify_signature(m_pk, m_prehash_function.has_value(), {}, sig, msg);
} catch(Decoding_Error&) {
return false;
}
}
std::string hash_function() const override { return m_prehash_function.value_or("SHAKE-256(912)"); }
private:
std::array<uint8_t, ED448_LEN> m_pk;
std::unique_ptr<Ed448_Message> m_message;
std::optional<std::string> m_prehash_function;
};
/**
* Ed448 signing operation
*/
class Ed448_Sign_Operation final : public PK_Ops::Signature {
public:
explicit Ed448_Sign_Operation(const Ed448_PrivateKey& key,
std::optional<std::string> prehash_function = std::nullopt) :
m_prehash_function(std::move(prehash_function)) {
const auto pk_bits = key.public_key_bits();
copy_mem(m_pk, std::span(pk_bits).first<ED448_LEN>());
const auto sk_bits = key.raw_private_key_bits();
BOTAN_ASSERT_NOMSG(sk_bits.size() == ED448_LEN);
m_sk.assign(sk_bits.begin(), sk_bits.end());
if(m_prehash_function) {
m_message = std::make_unique<Prehashed_Ed448_Message>(*m_prehash_function);
} else {
m_message = std::make_unique<Pure_Ed448_Message>();
}
}
void update(std::span<const uint8_t> input) override { m_message->update(input); }
std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
BOTAN_ASSERT_NOMSG(m_sk.size() == ED448_LEN);
auto scope = CT::scoped_poison(m_sk);
const auto sig = sign_message(
std::span(m_sk).first<ED448_LEN>(), m_pk, m_prehash_function.has_value(), {}, m_message->get_and_clear());
CT::unpoison(sig);
return {sig.begin(), sig.end()};
}
size_t signature_length() const override { return 2 * ED448_LEN; }
AlgorithmIdentifier algorithm_identifier() const override;
std::string hash_function() const override { return m_prehash_function.value_or("SHAKE-256(912)"); }
private:
std::array<uint8_t, ED448_LEN> m_pk;
secure_vector<uint8_t> m_sk;
std::unique_ptr<Ed448_Message> m_message;
std::optional<std::string> m_prehash_function;
};
AlgorithmIdentifier Ed448_Sign_Operation::algorithm_identifier() const {
return AlgorithmIdentifier(OID::from_string("Ed448"), AlgorithmIdentifier::USE_EMPTY_PARAM);
}
} // namespace
std::unique_ptr<PK_Ops::Verification> Ed448_PublicKey::create_verification_op(std::string_view params,
std::string_view provider) const {
if(provider == "base" || provider.empty()) {
if(params.empty() || params == "Identity" || params == "Pure" || params == "Ed448") {
return std::make_unique<Ed448_Verify_Operation>(*this);
} else if(params == "Ed448ph") {
return std::make_unique<Ed448_Verify_Operation>(*this, "SHAKE-256(512)");
} else {
return std::make_unique<Ed448_Verify_Operation>(*this, std::string(params));
}
}
throw Provider_Not_Found(algo_name(), provider);
}
std::unique_ptr<PK_Ops::Verification> Ed448_PublicKey::create_x509_verification_op(const AlgorithmIdentifier& alg_id,
std::string_view provider) const {
if(provider == "base" || provider.empty()) {
if(alg_id != this->algorithm_identifier()) {
throw Decoding_Error("Unexpected AlgorithmIdentifier for Ed448 X509 signature");
}
return std::make_unique<Ed448_Verify_Operation>(*this);
}
throw Provider_Not_Found(algo_name(), provider);
}
std::unique_ptr<PK_Ops::Signature> Ed448_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
std::string_view params,
std::string_view provider) const {
if(provider == "base" || provider.empty()) {
if(params.empty() || params == "Identity" || params == "Pure" || params == "Ed448") {
return std::make_unique<Ed448_Sign_Operation>(*this);
} else if(params == "Ed448ph") {
return std::make_unique<Ed448_Sign_Operation>(*this, "SHAKE-256(512)");
} else {
return std::make_unique<Ed448_Sign_Operation>(*this, std::string(params));
}
}
throw Provider_Not_Found(algo_name(), provider);
}
} // namespace Botan