#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 PublicKey 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); static optional fromData(const Stored &, const vector &); vector getData() const; Stored pub() const { return pub_; } template Stored> sign(const Stored &) const; template Stored> signAdd(const Stored> &) const; private: vector sign(const Digest &) const; const shared_ptr key; Stored pub_; }; class Signature { public: static Signature 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 Signed 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 Stored> SecretKey::signAdd(const Stored> & val) const { auto st = val.ref().storage(); auto sig = st.store(Signature(pub(), sign(val.ref().digest()))); auto sigs = val->sigs; sigs.push_back(st.store(Signature(pub(), sign(val->data.ref().digest())))); return st.store(Signed(val->data, sigs)); } template Signed Signed::load(const Ref & ref) { if (auto rec = ref->asRecord()) if (auto data = rec->item("SDATA").as()) { vector> sigs; for (const auto & sig : rec->items("sig").as()) if (sig->verify(data.value().ref())) sigs.push_back(sig); return Signed(*data, sigs); } return Signed(Stored::load(ref.storage().zref()), {}); } 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 PublicKexKey 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_; }; }