--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <decaf.hxx>
+#include <decaf/eddsa.hxx>
+#include <decaf/spongerng.hxx>
+
+#include "dnssecinfra.hh"
+
+using namespace decaf;
+
+class DecafED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit DecafED25519DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {
+
+ }
+ string getName() const override { return "Decaf ED25519"; }
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string getPubKeyHash() const override;
+ std::string sign(const std::string& msg) const override;
+ bool verify(const std::string& msg, const std::string& signature) const override;
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+ {}
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<DecafED25519DNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ unsigned char d_pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES];
+ unsigned char d_seckey[DECAF_EDDSA_25519_PRIVATE_BYTES];
+};
+
+void DecafED25519DNSCryptoKeyEngine::create(unsigned int bits)
+{
+ if(bits != (unsigned int)getBits()) {
+ throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED25519 class");
+ }
+
+ SpongeRng rng("/dev/urandom");
+
+ typename EdDSA<IsoEd25519>::PrivateKey priv(rng);
+ typename EdDSA<IsoEd25519>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+int DecafED25519DNSCryptoKeyEngine::getBits() const
+{
+ return DECAF_EDDSA_25519_PRIVATE_BYTES << 3;
+}
+
+DNSCryptoKeyEngine::storvector_t DecafED25519DNSCryptoKeyEngine::convertToISCVector() const
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 15 (ED25519)
+ PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
+ */
+
+ storvector_t storvector;
+
+ storvector.push_back(make_pair("Algorithm", "15 (ED25519)"));
+ storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES)));
+
+ return storvector;
+}
+
+void DecafED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap )
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 15 (ED25519)
+ PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
+ */
+
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ string privateKey = stormap["privatekey"];
+
+ if (privateKey.length() != DECAF_EDDSA_25519_PRIVATE_BYTES)
+ throw runtime_error("Private key size mismatch in ISCMap, DecafED25519 class");
+
+ typename EdDSA<IsoEd25519>::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_25519_PRIVATE_BYTES));
+ typename EdDSA<IsoEd25519>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+std::string DecafED25519DNSCryptoKeyEngine::getPubKeyHash() const
+{
+ return this->getPublicKeyString();
+}
+
+std::string DecafED25519DNSCryptoKeyEngine::getPublicKeyString() const
+{
+ return string((char*)d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES);
+}
+
+void DecafED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ if (input.length() != DECAF_EDDSA_25519_PUBLIC_BYTES)
+ throw runtime_error("Public key size mismatch, DecafED25519 class");
+
+ memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_25519_PUBLIC_BYTES);
+}
+
+std::string DecafED25519DNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ typename EdDSA<IsoEd25519>::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES));
+
+ SecureBuffer message(msg.begin(), msg.end());
+
+ SecureBuffer sig = priv.sign(message);
+
+ return string(sig.begin(), sig.end());
+}
+
+bool DecafED25519DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ if (signature.length() != DECAF_EDDSA_25519_SIGNATURE_BYTES)
+ return false;
+
+ typename EdDSA<IsoEd25519>::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES));
+
+ SecureBuffer sig(signature.begin(), signature.end());
+ SecureBuffer message(msg.begin(), msg.end());
+
+ try {
+ pub.verify(sig, message);
+ } catch(CryptoException) {
+ return false;
+ }
+
+ return true;
+}
+
+
+class DecafED448DNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit DecafED448DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {
+
+ }
+ string getName() const override { return "Decaf ED448"; }
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string getPubKeyHash() const override;
+ std::string sign(const std::string& msg) const override;
+ bool verify(const std::string& msg, const std::string& signature) const override;
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+ {}
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<DecafED448DNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ unsigned char d_pubkey[DECAF_EDDSA_448_PUBLIC_BYTES];
+ unsigned char d_seckey[DECAF_EDDSA_448_PRIVATE_BYTES];
+};
+
+void DecafED448DNSCryptoKeyEngine::create(unsigned int bits)
+{
+ if(bits != (unsigned int)getBits()) {
+ throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED448 class");
+ }
+
+ SpongeRng rng("/dev/urandom");
+
+ typename EdDSA<Ed448Goldilocks>::PrivateKey priv(rng);
+ typename EdDSA<Ed448Goldilocks>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+int DecafED448DNSCryptoKeyEngine::getBits() const
+{
+ return DECAF_EDDSA_448_PRIVATE_BYTES << 3;
+}
+
+DNSCryptoKeyEngine::storvector_t DecafED448DNSCryptoKeyEngine::convertToISCVector() const
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 16 (ED448)
+ PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA
+ */
+
+ storvector_t storvector;
+
+ storvector.push_back(make_pair("Algorithm", "16 (ED448)"));
+ storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES)));
+
+ return storvector;
+}
+
+void DecafED448DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap )
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 16 (ED448)
+ PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA
+ */
+
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ string privateKey = stormap["privatekey"];
+
+ if (privateKey.length() != DECAF_EDDSA_448_PRIVATE_BYTES)
+ throw runtime_error("Private key size mismatch in ISCMap, DecafED448 class");
+
+ typename EdDSA<Ed448Goldilocks>::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_448_PRIVATE_BYTES));
+ typename EdDSA<Ed448Goldilocks>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+std::string DecafED448DNSCryptoKeyEngine::getPubKeyHash() const
+{
+ return this->getPublicKeyString();
+}
+
+std::string DecafED448DNSCryptoKeyEngine::getPublicKeyString() const
+{
+ return string((char*)d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES);
+}
+
+void DecafED448DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ if (input.length() != DECAF_EDDSA_448_PUBLIC_BYTES)
+ throw runtime_error("Public key size mismatch, DecafED448 class");
+
+ memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_448_PUBLIC_BYTES);
+}
+
+std::string DecafED448DNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ typename EdDSA<Ed448Goldilocks>::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES));
+
+ SecureBuffer message(msg.begin(), msg.end());
+
+ SecureBuffer sig = priv.sign(message);
+
+ return string(sig.begin(), sig.end());
+}
+
+bool DecafED448DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ if (signature.length() != DECAF_EDDSA_448_SIGNATURE_BYTES)
+ return false;
+
+ typename EdDSA<Ed448Goldilocks>::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES));
+
+ SecureBuffer sig(signature.begin(), signature.end());
+ SecureBuffer message(msg.begin(), msg.end());
+
+ try {
+ pub.verify(sig, message);
+ } catch(CryptoException) {
+ return false;
+ }
+
+ return true;
+}
+
+
+namespace {
+struct LoaderDecafStruct
+{
+ LoaderDecafStruct()
+ {
+ DNSCryptoKeyEngine::report(15, &DecafED25519DNSCryptoKeyEngine::maker);
+ DNSCryptoKeyEngine::report(16, &DecafED448DNSCryptoKeyEngine::maker);
+ }
+} loaderdecaf;
+}