From c33c2e7e95d3f24a15e9fa3992ee7aa4be22fe5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Tue, 6 Sep 2016 12:06:21 -0400 Subject: [PATCH] crypto: add key, hash length parameters --- include/opendht/crypto.h | 11 ++++++++--- src/crypto.cpp | 33 ++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h index eaa28dd5..897abd25 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 cca5de87..36d006b5 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; } -- GitLab