#pragma once #include "storage.h" #include using std::nullopt; using std::optional; using std::shared_ptr; namespace erebos { template class Signed; class PublicKey { PublicKey(EVP_PKEY * key): key(key, EVP_PKEY_free) {} friend class SecretKey; public: static optional load(const Ref &); Ref store(const Storage &) const; const shared_ptr key; }; class SecretKey { SecretKey(EVP_PKEY * key, const Stored & pub): key(key, EVP_PKEY_free), pub_(pub) {} SecretKey(shared_ptr && key, const Stored & pub): key(key), pub_(pub) {} public: static SecretKey generate(const Storage & st); static optional load(const Stored & st); Stored pub() const { return pub_; } template Stored> sign(const Stored &) const; private: vector sign(const Digest &) const; const shared_ptr key; Stored pub_; }; class Signature { public: static optional load(const Ref &); Ref store(const Storage &) const; bool verify(const Ref &) const; Stored key; vector sig; private: friend class SecretKey; Signature(const Stored & key, const vector & sig): key(key), sig(sig) {} }; template class Signed { public: static optional> load(const Ref &); Ref store(const Storage &) const; bool isSignedBy(const Stored &) const; const Stored data; const vector> sigs; private: friend class SecretKey; Signed(const Stored & data, const vector> & sigs): data(data), sigs(sigs) {} }; template Stored> SecretKey::sign(const Stored & val) const { auto st = val.ref().storage(); auto sig = st.store(Signature(pub(), sign(val.ref().digest()))); return st.store(Signed(val, { sig })); } template optional> Signed::load(const Ref & ref) { auto rec = ref->asRecord(); if (!rec) return nullopt; auto data = rec->item("SDATA").as(); if (!data) return nullopt; vector> sigs; for (auto item : rec->items("sig")) if (auto sig = item.as()) if (sig.value()->verify(data.value().ref())) sigs.push_back(sig.value()); return Signed(*data, sigs); } template Ref Signed::store(const Storage & st) const { vector items; items.emplace_back("SDATA", data); for (const auto & sig : sigs) items.emplace_back("sig", sig); return st.storeObject(Record(std::move(items))); } template bool Signed::isSignedBy(const Stored & key) const { for (const auto & sig : sigs) if (sig->key == key) return true; return false; } class PublicKexKey { PublicKexKey(EVP_PKEY * key): key(key, EVP_PKEY_free) {} friend class SecretKexKey; public: static optional load(const Ref &); Ref store(const Storage &) const; const shared_ptr key; }; class SecretKexKey { SecretKexKey(EVP_PKEY * key, const Stored & pub): key(key, EVP_PKEY_free), pub_(pub) {} SecretKexKey(shared_ptr && key, const Stored & pub): key(key), pub_(pub) {} public: static SecretKexKey generate(const Storage & st); static optional load(const Stored & st); Stored pub() const { return pub_; } vector dh(const PublicKexKey &) const; private: const shared_ptr key; Stored pub_; }; }