diff --git a/include/opendht/value.h b/include/opendht/value.h
index 2298a57f6b598c6de7e0f217f2b6f27d784cf01c..d569a94de33bf6162bdec726d69993d4b3c7bbf2 100644
--- a/include/opendht/value.h
+++ b/include/opendht/value.h
@@ -638,8 +638,10 @@ struct OPENDHT_PUBLIC Value
      */
     unsigned priority {0};
 
+    bool checkSignature();
+    Sp<Value> decrypt(const crypto::PrivateKey& key);
+
 private:
-    friend class SecureDht;
     /* Cache for crypto ops */
     bool signatureChecked {false};
     bool signatureValid {false};
diff --git a/src/securedht.cpp b/src/securedht.cpp
index daaa3fe0df3193f230c982ff0b707d2e0b7dde17..d5a5015d6d64eeac2d8d9db3ba49f6822ecc7f62 100644
--- a/src/securedht.cpp
+++ b/src/securedht.cpp
@@ -72,36 +72,20 @@ ValueType
 SecureDht::secureType(ValueType&& type)
 {
     type.storePolicy = [this,type](InfoHash id, Sp<Value>& v, const InfoHash& nid, const SockAddr& a) {
-        if (v->isSigned()) {
-            if (!v->signatureChecked) {
-                v->signatureChecked = true;
-                v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
-            }
-            if (!v->signatureValid) {
-                if (logger_)
-                    logger_->w("Signature verification failed");
-                return false;
-            }
-        }
+        if (v->isSigned())
+            return v->checkSignature();
         return type.storePolicy(id, v, nid, a);
     };
     type.editPolicy = [this,type](InfoHash id, const Sp<Value>& o, Sp<Value>& n, const InfoHash& nid, const SockAddr& a) {
-        if (!o->isSigned())
+        if (not o->isSigned())
             return type.editPolicy(id, o, n, nid, a);
-        if (o->owner != n->owner) {
-            if (logger_)
-                logger_->w("Edition forbidden: owner changed.");
-            return false;
-        }
-        if (!n->signatureChecked) {
-            n->signatureChecked = true;
-            n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
-        }
-        if (!n->signatureValid) {
+        if (o->owner != n->owner or not n->isSigned()) {
             if (logger_)
                 logger_->w("Edition forbidden: signature verification failed.");
             return false;
         }
+        if (not n->checkSignature())
+            return false;
         if (o->seq == n->seq) {
             // If the data is exactly the same,
             // it can be reannounced, possibly by someone else.
@@ -253,19 +237,12 @@ SecureDht::checkValue(const Sp<Value>& v)
 #endif
             return {};
         }
-        if (v->decrypted) {
-            return v->decryptedValue;
-        }
-        v->decrypted = true;
         try {
-            Value decrypted_val (decrypt(*v));
-            if (decrypted_val.recipient == getId()) {
-                if (decrypted_val.owner)
-                    nodesPubKeys_[decrypted_val.owner->getId()] = decrypted_val.owner;
-                v->decryptedValue = std::make_shared<Value>(std::move(decrypted_val));
-                return v->decryptedValue;
+            if (auto decrypted_val = v->decrypt(*key_)) {
+                if (decrypted_val->owner)
+                    nodesPubKeys_[decrypted_val->owner->getId()] = decrypted_val->owner;
+                return decrypted_val;
             }
-            // Ignore values belonging to other people
         } catch (const std::exception& e) {
             if (logger_)
                 logger_->w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
@@ -273,17 +250,11 @@ SecureDht::checkValue(const Sp<Value>& v)
     }
     // Check signed values
     else if (v->isSigned()) {
-        if (v->signatureChecked) {
-            return v->signatureValid ? v : Sp<Value>{};
-        }
-        v->signatureChecked = true;
-        if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
-            v->signatureValid = true;
-            if (enableCache_)
+        if (v->checkSignature()) {
+            if (enableCache_ and v->owner)
                 nodesPubKeys_[v->owner->getId()] = v->owner;
             return v;
-        }
-        else if (logger_)
+        } else if (logger_)
             logger_->w("Signature verification failed for %s", v->toString().c_str());
     }
     // Forward normal values
diff --git a/src/value.cpp b/src/value.cpp
index 8252b56fe58a5b5c82026b1bb6c9c9a7e0d649f5..fc5da1d2e3142d793ebfcc5a6982c824f960c84f 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -239,6 +239,41 @@ Value::toJson() const
     return val;
 }
 
+bool
+Value::checkSignature()
+{
+    if (!signatureChecked) {
+        signatureChecked = true;
+        if (isSigned()) {
+            signatureValid = owner and owner->checkSignature(getToSign(), signature);
+        } else {
+            signatureValid = true;
+        }
+    }
+    return signatureValid;
+}
+
+Sp<Value>
+Value::decrypt(const crypto::PrivateKey& key)
+{
+    if (not decrypted) {
+        decrypted = true;
+        if (isEncrypted()) {
+            auto decryptedBlob = key.decrypt(cypher);
+            std::unique_ptr<Value> v {new Value(id)};
+            auto msg = msgpack::unpack((const char*)decryptedBlob.data(), decryptedBlob.size());
+            v->msgpack_unpack_body(msg.get());
+            if (v->recipient != key.getPublicKey().getId())
+                throw crypto::DecryptError("Recipient mismatch");
+            // Ignore values belonging to other people
+            if (not v->owner or not v->owner->checkSignature(v->getToSign(), v->signature))
+                throw crypto::DecryptError("Signature mismatch");
+            decryptedValue = std::move(v);
+        }
+    }
+    return decryptedValue;
+}
+
 uint64_t
 unpackId(const Json::Value& json, const std::string& key) {
     uint64_t ret = 0;