1 /*
2  *  Copyright (C) 2014-2019 Savoir-faire Linux Inc.
3  *  Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include "infohash.h"
22 #include "utils.h"
23 #include "rng.h"
24 
25 extern "C" {
26 #include <gnutls/gnutls.h>
27 #include <gnutls/abstract.h>
28 #include <gnutls/x509.h>
29 }
30 
31 #include <vector>
32 #include <memory>
33 
34 #ifdef _WIN32
35 #include <iso646.h>
36 #endif
37 
38 namespace dht {
39 
40 /**
41  * Contains all crypto primitives
42  */
43 namespace crypto {
44 
45 class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
46     public:
CryptoException(const std::string & str)47         CryptoException(const std::string& str) : std::runtime_error(str) {};
48 };
49 
50 /**
51  * Exception thrown when a decryption error happened.
52  */
53 class OPENDHT_PUBLIC DecryptError : public CryptoException {
54     public:
CryptoException(str)55         DecryptError(const std::string& str = "") : CryptoException(str) {};
56 };
57 
58 struct PrivateKey;
59 struct Certificate;
60 class RevocationList;
61 
62 using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>;
63 
64 /**
65  * A public key.
66  */
67 struct OPENDHT_PUBLIC PublicKey
68 {
69     PublicKey();
70 
71     /**
72      * Takes ownership of an existing gnutls_pubkey.
73      */
PublicKeyPublicKey74     PublicKey(gnutls_pubkey_t k) : pk(k) {}
75     PublicKey(const Blob& pk);
PublicKeyPublicKey76     PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
77 
78     ~PublicKey();
79     explicit operator bool() const { return pk; }
80     bool operator ==(const PublicKey& o) const {
81         return pk == o.pk || getId() == o.getId();
82     }
83     bool operator !=(const PublicKey& o) const {
84         return !(*this == o);
85     }
86 
87     PublicKey& operator=(PublicKey&& o) noexcept;
88 
89     /**
90      * Get public key fingerprint
91      */
92     InfoHash getId() const;
93 
94     /**
95      * Get public key long fingerprint
96      */
97     PkId getLongId() const;
98 
99     bool checkSignature(const Blob& data, const Blob& signature) const;
100     Blob encrypt(const Blob&) const;
101 
102     void pack(Blob& b) const;
103     void unpack(const uint8_t* dat, size_t dat_size);
104 
105     std::string toString() const;
106 
107     template <typename Packer>
msgpack_packPublicKey108     void msgpack_pack(Packer& p) const
109     {
110         Blob b;
111         pack(b);
112         p.pack_bin(b.size());
113         p.pack_bin_body((const char*)b.data(), b.size());
114     }
115 
116     void msgpack_unpack(msgpack::object o);
117 
118     gnutls_digest_algorithm_t getPreferredDigest() const;
119 
120     gnutls_pubkey_t pk {nullptr};
121 private:
122     PublicKey(const PublicKey&) = delete;
123     PublicKey& operator=(const PublicKey&) = delete;
124     void encryptBloc(const uint8_t* src, size_t src_size, uint8_t* dst, size_t dst_size) const;
125 };
126 
127 /**
128  * A private key, including the corresponding public key.
129  */
130 struct OPENDHT_PUBLIC PrivateKey
131 {
132     PrivateKey();
133     //PrivateKey(gnutls_privkey_t k) : key(k) {}
134 
135     /**
136      * Takes ownership of an existing gnutls_x509_privkey.
137      */
138     PrivateKey(gnutls_x509_privkey_t k);
139 
140     PrivateKey(PrivateKey&& o) noexcept;
141     PrivateKey& operator=(PrivateKey&& o) noexcept;
142 
143     PrivateKey(const Blob& import, const std::string& password = {});
144     ~PrivateKey();
145     explicit operator bool() const { return key; }
146 
147     PublicKey getPublicKey() const;
148     Blob serialize(const std::string& password = {}) const;
149 
150     /**
151      * Sign the provided binary object.
152      * @returns the signature data.
153      */
154     Blob sign(const Blob&) const;
155 
156     /**
157      * Try to decrypt the provided cypher text.
158      * In case of failure a CryptoException is thrown.
159      * @returns the decrypted data.
160      */
161     Blob decrypt(const Blob& cypher) const;
162 
163     /**
164      * Generate a new RSA key pair
165      * @param key_length : size of the modulus in bits
166      *      Minimim value: 2048
167      *      Recommended values: 4096, 8192
168      */
169     static PrivateKey generate(unsigned key_length = 4096);
170     static PrivateKey generateEC();
171 
172     gnutls_privkey_t key {};
173     gnutls_x509_privkey_t x509_key {};
174 private:
175     PrivateKey(const PrivateKey&) = delete;
176     PrivateKey& operator=(const PrivateKey&) = delete;
177     Blob decryptBloc(const uint8_t* src, size_t src_size) const;
178 
179     //friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
180 };
181 
182 
183 class OPENDHT_PUBLIC RevocationList
184 {
185     using clock = std::chrono::system_clock;
186     using time_point = clock::time_point;
187     using duration = clock::duration;
188 public:
189     RevocationList();
190     RevocationList(const Blob& b);
RevocationList(RevocationList && o)191     RevocationList(RevocationList&& o) noexcept : crl(o.crl) { o.crl = nullptr; }
192     ~RevocationList();
193 
194     RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
195 
196     void pack(Blob& b) const;
197     void unpack(const uint8_t* dat, size_t dat_size);
getPacked()198     Blob getPacked() const {
199         Blob b;
200         pack(b);
201         return b;
202     }
203 
204     template <typename Packer>
msgpack_pack(Packer & p)205     void msgpack_pack(Packer& p) const
206     {
207         Blob b = getPacked();
208         p.pack_bin(b.size());
209         p.pack_bin_body((const char*)b.data(), b.size());
210     }
211 
212     void msgpack_unpack(msgpack::object o);
213 
214     void revoke(const Certificate& crt, time_point t = time_point::min());
215 
216     bool isRevoked(const Certificate& crt) const;
217 
218     /**
219      * Sign this revocation list using provided key and certificate.
220      * Validity_period sets the duration until next update (default to no next update).
221      */
222     void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
sign(const Identity & id)223     void sign(const Identity& id) { sign(*id.first, *id.second); }
224 
225     bool isSignedBy(const Certificate& issuer) const;
226 
227     std::string toString() const;
228 
229     /**
230      * Read the CRL number extension field.
231      */
232     Blob getNumber() const;
233 
234     /** Read CRL issuer Common Name (CN) */
235     std::string getIssuerName() const;
236 
237     /** Read CRL issuer User ID (UID) */
238     std::string getIssuerUID() const;
239 
240     time_point getUpdateTime() const;
241     time_point getNextUpdateTime() const;
242 
get()243     gnutls_x509_crl_t get() { return crl; }
getCopy()244     gnutls_x509_crl_t getCopy() const {
245         if (not crl)
246             return nullptr;
247         auto copy = RevocationList(getPacked());
248         gnutls_x509_crl_t ret = copy.crl;
249         copy.crl = nullptr;
250         return ret;
251     }
252 
253 private:
254     gnutls_x509_crl_t crl {};
255     RevocationList(const RevocationList&) = delete;
256     RevocationList& operator=(const RevocationList&) = delete;
257 };
258 
259 enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
260 
261 class OPENDHT_PUBLIC CertificateRequest {
262 public:
263     CertificateRequest();
264     CertificateRequest(const uint8_t* data, size_t size);
CertificateRequest(const Blob & data)265     CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
266 
CertificateRequest(CertificateRequest && o)267     CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
268         o.request = nullptr;
269     }
270     CertificateRequest& operator=(CertificateRequest&& o) noexcept;
271 
272     ~CertificateRequest();
273 
274     void setName(const std::string& name);
275     void setUID(const std::string& name);
276     void setAltName(NameType type, const std::string& name);
277 
278     std::string getName() const;
279     std::string getUID() const;
280 
281     void sign(const PrivateKey& key, const std::string& password = {});
282 
283     bool verify() const;
284 
285     Blob pack() const;
286 
get()287     gnutls_x509_crq_t get() const { return request; }
288 private:
289     CertificateRequest(const CertificateRequest& o) = delete;
290     CertificateRequest& operator=(const CertificateRequest& o) = delete;
291     gnutls_x509_crq_t request {nullptr};
292 };
293 
294 struct OPENDHT_PUBLIC Certificate {
CertificateCertificate295     Certificate() noexcept {}
296 
297     /**
298      * Take ownership of existing gnutls structure
299      */
CertificateCertificate300     Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
301 
CertificateCertificate302     Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
303 
304     /**
305      * Import certificate (PEM or DER) or certificate chain (PEM),
306      * ordered from subject to issuer
307      */
308     Certificate(const Blob& crt);
CertificateCertificate309     Certificate(const std::string& pem) : cert(nullptr) {
310         unpack((const uint8_t*)pem.data(), pem.size());
311     }
CertificateCertificate312     Certificate(const uint8_t* dat, size_t dat_size) : cert(nullptr) {
313         unpack(dat, dat_size);
314     }
315 
316     /**
317      * Import certificate chain (PEM or DER),
318      * ordered from subject to issuer
319      */
320     template<typename Iterator>
CertificateCertificate321     Certificate(const Iterator& begin, const Iterator& end) {
322         unpack(begin, end);
323     }
324 
325     /**
326      * Import certificate chain (PEM or DER),
327      * ordered from subject to issuer
328      */
329     template<typename Iterator>
CertificateCertificate330     Certificate(const std::vector<std::pair<Iterator, Iterator>>& certs) {
331         unpack(certs);
332     }
333 
334     Certificate& operator=(Certificate&& o) noexcept;
335     ~Certificate();
336 
337     void pack(Blob& b) const;
338     void unpack(const uint8_t* dat, size_t dat_size);
getPackedCertificate339     Blob getPacked() const {
340         Blob b;
341         pack(b);
342         return b;
343     }
344 
345     /**
346      * Import certificate chain (PEM or DER).
347      * Certificates are not checked during import.
348      *
349      * Iterator is the type of an iterator or pointer to
350      * gnutls_x509_crt_t or Blob instances to import, that should be
351      * ordered from subject to issuer.
352      */
353     template<typename Iterator>
unpackCertificate354     void unpack(const Iterator& begin, const Iterator& end)
355     {
356         std::shared_ptr<Certificate> tmp_subject {};
357         std::shared_ptr<Certificate> first {};
358         for (Iterator icrt = begin; icrt < end; ++icrt) {
359             auto tmp_crt = std::make_shared<Certificate>(*icrt);
360             if (tmp_subject)
361                 tmp_subject->issuer = tmp_crt;
362             tmp_subject = std::move(tmp_crt);
363             if (!first)
364                 first = tmp_subject;
365         }
366         *this = first ? std::move(*first) : Certificate();
367     }
368 
369     /**
370      * Import certificate chain (PEM or DER).
371      * Certificates are not checked during import.
372      *
373      * Iterator is the type of an iterator or pointer to the bytes of
374      * the certificates to import.
375      *
376      * @param certs list of (begin, end) iterator pairs, pointing to the
377      *              PEM or DER certificate data to import, that should be
378      *              ordered from subject to issuer.
379      */
380     template<typename Iterator>
unpackCertificate381     void unpack(const std::vector<std::pair<Iterator, Iterator>>& certs)
382     {
383         std::shared_ptr<Certificate> tmp_issuer;
384         // reverse iteration
385         for (auto li = certs.rbegin(); li != certs.rend(); ++li) {
386             Certificate tmp_crt;
387             gnutls_x509_crt_init(&tmp_crt.cert);
388             const gnutls_datum_t crt_dt {(uint8_t*)&(*li->first), (unsigned)(li->second-li->first)};
389             int err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_PEM);
390             if (err != GNUTLS_E_SUCCESS)
391                 err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_DER);
392             if (err != GNUTLS_E_SUCCESS)
393                 throw CryptoException(std::string("Could not read certificate - ") + gnutls_strerror(err));
394             tmp_crt.issuer = tmp_issuer;
395             tmp_issuer = std::make_shared<Certificate>(std::move(tmp_crt));
396         }
397         *this = tmp_issuer ? std::move(*tmp_issuer) : Certificate();
398     }
399 
400     template <typename Packer>
msgpack_packCertificate401     void msgpack_pack(Packer& p) const
402     {
403         Blob b;
404         pack(b);
405         p.pack_bin(b.size());
406         p.pack_bin_body((const char*)b.data(), b.size());
407     }
408 
409     void msgpack_unpack(msgpack::object o);
410 
411     explicit operator bool() const { return cert; }
412     PublicKey getPublicKey() const;
413 
414     /** Same as getPublicKey().getId() */
415     InfoHash getId() const;
416     /** Same as getPublicKey().getLongId() */
417     PkId getLongId() const;
418 
419     /** Read certificate Common Name (CN) */
420     std::string getName() const;
421 
422     /** Read certificate User ID (UID) */
423     std::string getUID() const;
424 
425     /** Read certificate issuer Common Name (CN) */
426     std::string getIssuerName() const;
427 
428     /** Read certificate issuer User ID (UID) */
429     std::string getIssuerUID() const;
430 
431     /** Read certificate alternative names */
432     std::vector<std::pair<NameType, std::string>> getAltNames() const;
433 
434     std::chrono::system_clock::time_point getActivation() const;
435     std::chrono::system_clock::time_point getExpiration() const;
436 
437     /**
438      * Returns true if the certificate is marked as a Certificate Authority
439      * and has necessary key usage flags to sign certificates.
440      */
441     bool isCA() const;
442 
443     /**
444      * PEM encoded certificate.
445      * If chain is true, the issuer chain will be included (default).
446      */
447     std::string toString(bool chain = true) const;
448 
449     std::string print() const;
450 
451     /**
452      * As a CA, revoke a certificate, adding it to
453      * the attached Certificate Revocation List (CRL)
454      */
455     void revoke(const PrivateKey&, const Certificate&);
456 
457     /**
458      * Get the list of certificates revoked as as CA.
459      */
460     std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
461 
462     /**
463      * Attach existing revocation list.
464      */
465     void addRevocationList(RevocationList&&);
466     void addRevocationList(std::shared_ptr<RevocationList>);
467 
468     static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
469     static Certificate generate(const CertificateRequest& request, const Identity& ca);
470 
getCopyCertificate471     gnutls_x509_crt_t getCopy() const {
472         if (not cert)
473             return nullptr;
474         auto copy = Certificate(getPacked());
475         gnutls_x509_crt_t ret = copy.cert;
476         copy.cert = nullptr;
477         return ret;
478     }
479 
480     std::vector<gnutls_x509_crt_t>
481     getChain(bool copy = false) const
482     {
483         if (not cert)
484             return {};
485         std::vector<gnutls_x509_crt_t> crts;
486         for (auto c = this; c; c = c->issuer.get())
487             crts.emplace_back(copy ? c->getCopy() : c->cert);
488         return crts;
489     }
490 
491     std::pair<
492         std::vector<gnutls_x509_crt_t>,
493         std::vector<gnutls_x509_crl_t>
494     >
495     getChainWithRevocations(bool copy = false) const
496     {
497         if (not cert)
498             return {};
499         std::vector<gnutls_x509_crt_t> crts;
500         std::vector<gnutls_x509_crl_t> crls;
501         for (auto c = this; c; c = c->issuer.get()) {
502             crts.emplace_back(copy ? c->getCopy() : c->cert);
503             crls.reserve(crls.size() + c->revocation_lists.size());
504             for (const auto& crl : c->revocation_lists)
505                 crls.emplace_back(copy ? crl->getCopy() : crl->get());
506         }
507         return {crts, crls};
508     }
509 
510     gnutls_digest_algorithm_t getPreferredDigest() const;
511 
512     gnutls_x509_crt_t cert {nullptr};
513     std::shared_ptr<Certificate> issuer {};
514 private:
515     Certificate(const Certificate&) = delete;
516     Certificate& operator=(const Certificate&) = delete;
517 
518     struct crlNumberCmp {
operatorCertificate::crlNumberCmp519         bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
520             return lhs->getNumber() < rhs->getNumber();
521         }
522     };
523 
524     std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
525 };
526 
527 struct OPENDHT_PUBLIC TrustList
528 {
529     struct VerifyResult {
530         int ret;
531         unsigned result;
hasErrorTrustList::VerifyResult532         bool hasError() const { return ret < 0; }
isValidTrustList::VerifyResult533         bool isValid() const { return !hasError() and !(result & GNUTLS_CERT_INVALID); }
534         explicit operator bool() const { return isValid(); }
535         std::string toString() const;
536         OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const VerifyResult& h);
537     };
538 
539     TrustList();
TrustListTrustList540     TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
541         o.trust = nullptr;
542     }
543     TrustList& operator=(TrustList&& o) noexcept;
544     ~TrustList();
545     void add(const Certificate& crt);
546     void add(const RevocationList& crl);
547     void remove(const Certificate& crt, bool parents = true);
548     VerifyResult verify(const Certificate& crt) const;
549 
550 private:
551     TrustList(const TrustList& o) = delete;
552     TrustList& operator=(const TrustList& o) = delete;
553     gnutls_x509_trust_list_t trust {nullptr};
554 };
555 
556 template <class T>
557 class OPENDHT_PUBLIC secure_vector
558 {
559 public:
secure_vector()560     secure_vector() {}
561     secure_vector(secure_vector<T> const&) = default;
562     secure_vector(secure_vector<T> &&) = default;
secure_vector(unsigned size)563     explicit secure_vector(unsigned size): data_(size) {}
secure_vector(unsigned size,T _item)564     explicit secure_vector(unsigned size, T _item): data_(size, _item) {}
secure_vector(const std::vector<T> & c)565     explicit secure_vector(const std::vector<T>& c): data_(c) {}
secure_vector(std::vector<T> && c)566     secure_vector(std::vector<T>&& c): data_(std::move(c)) {}
~secure_vector()567     ~secure_vector() { clean(); }
568 
getRandom(size_t size)569     static secure_vector<T> getRandom(size_t size) {
570         secure_vector<T> ret(size);
571         crypto::random_device rdev;
572 #ifdef _WIN32
573         std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
574 #else
575         std::uniform_int_distribution<uint8_t> rand_byte;
576 #endif
577         std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
578         return ret;
579     }
580     secure_vector<T>& operator=(const secure_vector<T>& c) {
581         if (&c == this)
582             return *this;
583         clean();
584         data_ = c.data_;
585         return *this;
586     }
587     secure_vector<T>& operator=(secure_vector<T>&& c) {
588         if (&c == this)
589             return *this;
590         clean();
591         data_ = std::move(c.data_);
592         return *this;
593     }
594     secure_vector<T>& operator=(std::vector<T>&& c) {
595         clean();
596         data_ = std::move(c);
597         return *this;
598     }
writable()599     std::vector<T>& writable() { clean(); return data_; }
makeInsecure()600     const std::vector<T>& makeInsecure() const { return data_; }
data()601     const uint8_t* data() const { return data_.data(); }
602 
clean()603     void clean() {
604         clean(data_.begin(), data_.end());
605     }
606 
clear()607     void clear() { clean(); data_.clear(); }
608 
size()609     size_t size() const { return data_.size(); }
empty()610     bool empty() const { return data_.empty(); }
611 
swap(secure_vector<T> & other)612     void swap(secure_vector<T>& other) { data_.swap(other.data_); }
resize(size_t s)613     void resize(size_t s) {
614         if (s == data_.size()) return;
615         if (s < data_.size()) {
616             //shrink
617             clean(data_.begin()+s, data_.end());
618             data_.resize(s);
619         } else {
620             //grow
621             auto data = std::move(data_); // move protected data
622             clear();
623             data_.resize(s);
624             std::copy(data.begin(), data.end(), data_.begin());
625             clean(data.begin(), data.end());
626         }
627     }
628 
629 private:
630     /**
631      * Securely wipe memory
632      */
clean(const typename std::vector<T>::iterator & i,const typename std::vector<T>::iterator & j)633     static void clean(const typename std::vector<T>::iterator& i, const typename std::vector<T>::iterator& j) {
634         volatile uint8_t* b = reinterpret_cast<uint8_t*>(&*i);
635         volatile uint8_t* e = reinterpret_cast<uint8_t*>(&*j);
636         std::fill(b, e, 0);
637     }
638 
639     std::vector<T> data_;
640 };
641 
642 using SecureBlob = secure_vector<uint8_t>;
643 
644 /**
645  * Generate an RSA key pair (4096 bits) and a certificate.
646  * @param name the name used in the generated certificate
647  * @param ca if set, the certificate authority that will sign the generated certificate.
648  *           If not set, the generated certificate will be a self-signed CA.
649  * @param key_length stength of the generated private key (bits).
650  */
651 OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca);
652 OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", const Identity& ca = {}, unsigned key_length = 4096);
653 
654 OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
655 OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
656 
657 OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
658 
659 /**
660  * Performs SHA512, SHA256 or SHA1, depending on hash_length.
661  * Attempts to choose an hash function with
662  * output size of at least hash_length bytes, Current implementation
663  * will use SHA1 for hash_length up to 20 bytes,
664  * will use SHA256 for hash_length up to 32 bytes,
665  * will use SHA512 for hash_length of 33 bytes and more.
666  */
667 OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
668 
669 OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
670 
671 /**
672  * Generates an encryption key from a text password,
673  * making the key longer to bruteforce.
674  * The generated key also depends on a unique salt value of any size,
675  * that can be transmitted in clear, and will be generated if
676  * not provided (32 bytes).
677  */
678 OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
679 
680 /**
681  * AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
682  */
683 OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const Blob& key);
684 OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
685 
686 /**
687  * AES-GCM decryption.
688  */
689 OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
690 OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
691 
692 }
693 }
694