From 426c6b6e6d328112a28059790c92722f152753b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Tue, 14 Jun 2016 18:13:02 -0400
Subject: [PATCH] value: add common crypto ops

---
 include/opendht/securedht.h |  9 +++-----
 include/opendht/value.h     | 45 ++++++++++++++++++++++++++++++++++++-
 src/securedht.cpp           | 19 +++++-----------
 src/value.cpp               |  5 +++--
 4 files changed, 55 insertions(+), 23 deletions(-)

diff --git a/include/opendht/securedht.h b/include/opendht/securedht.h
index a41ecf26..d5b5e6d0 100644
--- a/include/opendht/securedht.h
+++ b/include/opendht/securedht.h
@@ -126,16 +126,13 @@ public:
     Value decrypt(const Value& v);
 
     void findCertificate(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb);
-    void findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::PublicKey>)> cb);
+    void findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<const crypto::PublicKey>)> cb);
 
     const std::shared_ptr<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
     void registerCertificate(std::shared_ptr<crypto::Certificate>& cert);
 
     const std::shared_ptr<crypto::Certificate> getCertificate(const InfoHash& node) const;
-    const std::shared_ptr<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
-
-
-    
+    const std::shared_ptr<const crypto::PublicKey> getPublicKey(const InfoHash& node) const;
 
     /**
      * Allows to set a custom callback called by the library to find a locally-stored certificate.
@@ -161,7 +158,7 @@ private:
 
     // our certificate cache
     std::map<InfoHash, std::shared_ptr<crypto::Certificate>> nodesCertificates_ {};
-    std::map<InfoHash, std::shared_ptr<crypto::PublicKey>> nodesPubKeys_ {};
+    std::map<InfoHash, std::shared_ptr<const crypto::PublicKey>> nodesPubKeys_ {};
 
     std::uniform_int_distribution<Value::Id> rand_id {};
 };
diff --git a/include/opendht/value.h b/include/opendht/value.h
index 9990147d..58351e70 100644
--- a/include/opendht/value.h
+++ b/include/opendht/value.h
@@ -248,6 +248,43 @@ struct Value
         return owner and not signature.empty();
     }
 
+    /**
+     * Sign the value using the provided private key.
+     * Afterward, checkSignature() will return true and owner will
+     * be set to the corresponding public key.
+     */
+    void sign(const crypto::PrivateKey& key) {
+        if (isEncrypted())
+            throw DhtException("Can't sign encrypted data.");
+        owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
+        signature = key.sign(getToSign());
+    }
+
+    /**
+     * Check that the value is signed and that the signature matches.
+     * If true, the owner field will contain the signer public key.
+     */
+    bool checkSignature() const {
+        return isSigned() and owner->checkSignature(getToSign(), signature);
+    }
+
+    std::shared_ptr<const crypto::PublicKey> getOwner() const {
+        return std::static_pointer_cast<const crypto::PublicKey>(owner);
+    }
+
+    /**
+     * Sign the value with from and returns the encrypted version for to.
+     */
+    Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
+        if (isEncrypted())
+            throw DhtException("Data is already encrypted.");
+        setRecipient(to.getId());
+        sign(from);
+        Value nv {id};
+        nv.setCypher(to.encrypt(getToEncrypt()));
+        return nv;
+    }
+
     Value() {}
 
     Value (Id id) : id(id) {}
@@ -380,13 +417,19 @@ struct Value
 
     void msgpack_unpack(msgpack::object o);
     void msgpack_unpack_body(const msgpack::object& o);
+    Blob getPacked() const {
+        msgpack::sbuffer buffer;
+        msgpack::packer<msgpack::sbuffer> pk(&buffer);
+        pk.pack(*this);
+        return {buffer.data(), buffer.data()+buffer.size()};
+    }
 
     Id id {INVALID_ID};
 
     /**
      * Public key of the signer.
      */
-    std::shared_ptr<crypto::PublicKey> owner {};
+    std::shared_ptr<const crypto::PublicKey> owner {};
 
     /**
      * Hash of the recipient (optional).
diff --git a/src/securedht.cpp b/src/securedht.cpp
index f1718ee9..aafda7ee 100644
--- a/src/securedht.cpp
+++ b/src/securedht.cpp
@@ -141,7 +141,7 @@ SecureDht::getCertificate(const InfoHash& node) const
         return it->second;
 }
 
-const std::shared_ptr<crypto::PublicKey>
+const std::shared_ptr<const crypto::PublicKey>
 SecureDht::getPublicKey(const InfoHash& node) const
 {
     if (node == getId())
@@ -226,7 +226,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const std::s
 }
 
 void
-SecureDht::findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::PublicKey>)> cb)
+SecureDht::findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<const crypto::PublicKey>)> cb)
 {
     auto pk = getPublicKey(node);
     if (pk && *pk) {
@@ -342,7 +342,7 @@ SecureDht::putSigned(const InfoHash& hash, std::shared_ptr<Value> val, DoneCallb
 void
 SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, std::shared_ptr<Value> val, DoneCallback callback, bool permanent)
 {
-    findPublicKey(to, [=](const std::shared_ptr<crypto::PublicKey> pk) {
+    findPublicKey(to, [=](const std::shared_ptr<const crypto::PublicKey> pk) {
         if(!pk || !*pk) {
             if (callback)
                 callback(false, {});
@@ -362,22 +362,13 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, std::shared_pt
 void
 SecureDht::sign(Value& v) const
 {
-    if (v.isEncrypted())
-        throw DhtException("Can't sign encrypted data.");
-    v.owner = std::make_shared<crypto::PublicKey>(key_->getPublicKey());
-    v.signature = key_->sign(v.getToSign());
+    v.sign(*key_);
 }
 
 Value
 SecureDht::encrypt(Value& v, const crypto::PublicKey& to) const
 {
-    if (v.isEncrypted())
-        throw DhtException("Data is already encrypted.");
-    v.setRecipient(to.getId());
-    sign(v);
-    Value nv {v.id};
-    nv.setCypher(to.encrypt(v.getToEncrypt()));
-    return nv;
+    return v.encrypt(*key_, to);
 }
 
 Value
diff --git a/src/value.cpp b/src/value.cpp
index a2c4d1e6..58a86556 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -142,8 +142,9 @@ Value::msgpack_unpack_body(const msgpack::object& o)
                 seq = rseq->as<decltype(seq)>();
             else
                 throw msgpack::type_error();
-            owner = std::make_shared<crypto::PublicKey>();
-            owner->msgpack_unpack(*rowner);
+            crypto::PublicKey new_owner;
+            new_owner.msgpack_unpack(*rowner);
+            owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
             if (auto rrecipient = findMapValue(*rbody, "to")) {
                 recipient = rrecipient->as<InfoHash>();
             }
-- 
GitLab