diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h
index eaa28dd5c86c477bae179ea979b9b253b8514780..897abd255d2e5a84ba506ecb8bd0248f46d62858 100644
--- a/include/opendht/crypto.h
+++ b/include/opendht/crypto.h
@@ -329,9 +329,14 @@ Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {},
 
 
 /**
- * SHA512
+ * Performs SHA512, SHA256 or SHA1, depending on hash_length.
+ * Attempts to choose an hash function with
+ * output size of at least hash_length bytes, Current implementation
+ * will use SHA1 for hash_length up to 20 bytes,
+ * will use SHA256 for hash_length up to 32 bytes,
+ * will use SHA512 for hash_length of 33 bytes and more.
  */
-Blob hash(const Blob& data);
+Blob hash(const Blob& data, size_t hash_length = 512/8);
 
 /**
  * Generates an encryption key from a text password,
@@ -340,7 +345,7 @@ Blob hash(const Blob& data);
  * that can be transmitted in clear, and will be generated if
  * not provided (32 bytes).
  */
-Blob stretchKey(const std::string& password, Blob& salt);
+Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
 
 /**
  * AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
diff --git a/src/crypto.cpp b/src/crypto.cpp
index cca5de87f7e091b092605be198aabcdede3f05cb..36d006b518c9eae0e2a6f39485ecec65f5b18771 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -83,6 +83,18 @@ namespace crypto {
 static constexpr std::array<size_t, 3> AES_LENGTHS {{128/8, 192/8, 256/8}};
 static constexpr size_t PASSWORD_SALT_LENGTH {16};
 
+constexpr gnutls_digest_algorithm_t gnutlsHashAlgo(size_t min_res) {
+    return (min_res > 256/8) ? GNUTLS_DIG_SHA512 : (
+           (min_res > 128/8) ? GNUTLS_DIG_SHA256 : (
+                               GNUTLS_DIG_SHA1));
+}
+
+constexpr size_t gnutlsHashSize(int algo) {
+    return (algo == GNUTLS_DIG_SHA512) ? 512/8 : (
+           (algo == GNUTLS_DIG_SHA256) ? 256/8 : (
+           (algo == GNUTLS_DIG_SHA1)   ? 160/8 : 0 ));
+}
+
 size_t aesKeySize(size_t max)
 {
     size_t aes_key_len = 0;
@@ -108,7 +120,7 @@ bool aesKeySizeGood(size_t key_size)
 Blob aesEncrypt(const Blob& data, const Blob& key)
 {
     if (not aesKeySizeGood(key.size()))
-        throw DecryptError("Wrong key size");
+        throw DecryptError("Wrong key size: " + std::to_string(key.size()));
 
     Blob ret(data.size() + GCM_IV_SIZE + GCM_DIGEST_SIZE);
     {
@@ -128,8 +140,7 @@ Blob aesEncrypt(const Blob& data, const Blob& key)
 Blob aesEncrypt(const Blob& data, const std::string& password)
 {
     Blob salt;
-    Blob key = stretchKey(password, salt);
-    key.resize(256 / 8);
+    Blob key = stretchKey(password, salt, 256 / 8);
     Blob encrypted = aesEncrypt(data, key);
     encrypted.insert(encrypted.begin(), salt.begin(), salt.end());
     return encrypted;
@@ -175,13 +186,12 @@ Blob aesDecrypt(const Blob& data, const std::string& password)
     if (data.size() <= PASSWORD_SALT_LENGTH)
         throw DecryptError("Wrong data size");    
     Blob salt {data.begin(), data.begin()+PASSWORD_SALT_LENGTH};
-    Blob key = stretchKey(password, salt);
-    key.resize(256 / 8);
+    Blob key = stretchKey(password, salt, 256/8);
     Blob encrypted {data.begin()+PASSWORD_SALT_LENGTH, data.end()};
     return aesDecrypt(encrypted, key);
 }
 
-Blob stretchKey(const std::string& password, Blob& salt)
+Blob stretchKey(const std::string& password, Blob& salt, size_t key_length)
 {
     if (salt.empty()) {
         salt.resize(PASSWORD_SALT_LENGTH);
@@ -193,18 +203,19 @@ Blob stretchKey(const std::string& password, Blob& salt)
     auto ret = argon2i_hash_raw(16, 64*1024, 1, password.data(), password.size(), salt.data(), salt.size(), res.data(), res.size());
     if (ret != ARGON2_OK)
         throw CryptoException("Can't compute argon2i !");
-    return hash(res);
+    return hash(res, key_length);
 }
 
-Blob hash(const Blob& data)
+Blob hash(const Blob& data, size_t hash_len)
 {
+    auto algo = gnutlsHashAlgo(hash_len);    
+    size_t res_size = gnutlsHashSize(algo);
     Blob res;
-    size_t res_size = 64;
     res.resize(res_size);
     const gnutls_datum_t gdat {(uint8_t*)data.data(), (unsigned)data.size()};
-    if (gnutls_fingerprint(GNUTLS_DIG_SHA512, &gdat, res.data(), &res_size))
+    if (gnutls_fingerprint(algo, &gdat, res.data(), &res_size))
         throw CryptoException("Can't compute hash !");
-    res.resize(res_size);
+    res.resize(std::min(hash_len, res_size));
     return res;
 }