Hello, I would like to contribute an implementation of balloon password hashing algorithm to Nettle. Output of this implementation is consistent with implementations found on Wikipedia like: python: https://github.com/nachonavarro/balloon-hashing rust: https://github.com/RustCrypto/password-hashes/tree/master/balloon-hash go: https://github.com/nogoegst/balloon Currently the patch does not use Nettle formatting, I will change the format after there are no other issues with the patch. Could you please review the attached patch and give me your feedback?
Kind regards, Zoltan
diff --color -ruNp a/balloon.c b/balloon.c --- a/balloon.c 1970-01-01 01:00:00.000000000 +0100 +++ b/balloon.c 2022-08-18 16:45:09.598416229 +0200 @@ -0,0 +1,131 @@ +/* balloon.c - Balloon password-hashing algorithm + + Copyright (C) 2022 Zoltan Fridrich + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "balloon.h" +#include "macros.h" +#include "nettle-internal.h" + +#define DELTA 3 + +static inline void +hash(const struct nettle_hash *alg, + uint64_t cnt, + size_t a_len, const uint8_t *a, + size_t b_len, const uint8_t *b, + uint8_t *result) +{ + uint8_t ctx[NETTLE_MAX_HASH_CONTEXT_SIZE]; + uint8_t tmp[sizeof(uint64_t)]; + + alg->init(ctx); + LE_WRITE_UINT64(tmp, cnt); + alg->update(ctx, sizeof(tmp), tmp); + alg->update(ctx, a_len, a); + alg->update(ctx, b_len, b); + alg->digest(ctx, alg->digest_size, result); +} + +static inline void +hash_ints(const struct nettle_hash *alg, + uint64_t i, uint64_t j, uint64_t k, uint8_t *result) +{ + uint8_t ctx[NETTLE_MAX_HASH_CONTEXT_SIZE]; + uint8_t tmp[sizeof(uint64_t)]; + + alg->init(ctx); + LE_WRITE_UINT64(tmp, i); + alg->update(ctx, sizeof(tmp), tmp); + LE_WRITE_UINT64(tmp, j); + alg->update(ctx, sizeof(tmp), tmp); + LE_WRITE_UINT64(tmp, k); + alg->update(ctx, sizeof(tmp), tmp); + alg->digest(ctx, alg->digest_size, result); +} + +static inline unsigned +block_to_int(size_t length, const uint8_t *block, unsigned mod) +{ + unsigned r = 0; + + for (int i = length - 1; i >= 0; --i) { + r <<= 8; + r += (block[i] & 0xFF); + r %= mod; + } + return r; +} + +int +balloon(size_t passwd_len, const uint8_t *passwd, + size_t salt_len, const uint8_t *salt, + unsigned s_cost, unsigned t_cost, + const struct nettle_hash *alg, uint8_t *result) +{ + const unsigned BS = alg->digest_size; + unsigned i, j, k, cnt = 0; + uint8_t *buf; + + buf = malloc(s_cost * BS); + if (buf == NULL) + return 0; + + TMP_DECL(block, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_ALLOC(block, BS); + + hash(alg, cnt++, passwd_len, passwd, salt_len, salt, buf); + for (i = 1; i < s_cost; ++i) + hash(alg, cnt++, BS, buf + (i - 1) * BS, 0, NULL, buf + i * BS); + + for (i = 0; i < t_cost; ++i) { + for (j = 0; j < s_cost; ++j) { + hash(alg, cnt++, BS, buf + (j ? j - 1 : s_cost - 1) * BS, + BS, buf + j * BS, buf + j * BS); + for (k = 0; k < DELTA; ++k) { + hash_ints(alg, i, j, k, block); + hash(alg, cnt++, salt_len, salt, BS, block, block); + hash(alg, cnt++, BS, buf + j * BS, + BS, buf + block_to_int(BS, block, s_cost) * BS, + buf + j * BS); + } + } + } + memcpy(result, buf + (s_cost - 1) * BS, BS); + + free(buf); + return 1; +} diff --color -ruNp a/balloon.h b/balloon.h --- a/balloon.h 1970-01-01 01:00:00.000000000 +0100 +++ b/balloon.h 2022-08-18 15:38:56.204538854 +0200 @@ -0,0 +1,54 @@ +/* balloon.h - Balloon password-hashing algorithm + + Copyright (C) 2022 Zoltan Fridrich + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#ifndef NETTLE_BALLOON_H_INCLUDED +#define NETTLE_BALLOON_H_INCLUDED + +#include "nettle-meta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define balloon nettle_balloon + +int +balloon(size_t passwd_len, const uint8_t *passwd, + size_t salt_len, const uint8_t *salt, + unsigned s_cost, unsigned t_cost, + const struct nettle_hash *alg, uint8_t *result); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_BALLOON_H_INCLUDED */ diff --color -ruNp a/Makefile.in b/Makefile.in --- a/Makefile.in 2022-08-03 15:22:54.207789385 +0200 +++ b/Makefile.in 2022-08-18 16:18:39.330463813 +0200 @@ -82,7 +82,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes256-meta.c \ nist-keywrap.c \ arcfour.c arcfour-crypt.c \ - arctwo.c arctwo-meta.c blowfish.c blowfish-bcrypt.c \ + arctwo.c arctwo-meta.c balloon.c blowfish.c blowfish-bcrypt.c \ base16-encode.c base16-decode.c base16-meta.c \ base64-encode.c base64-decode.c base64-meta.c \ base64url-encode.c base64url-decode.c base64url-meta.c \ @@ -218,7 +218,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \ OPT_SOURCES = fat-arm.c fat-arm64.c fat-ppc.c fat-s390x.c fat-x86_64.c mini-gmp.c -HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \ +HEADERS = aes.h arcfour.h arctwo.h asn1.h balloon.h blowfish.h \ base16.h base64.h bignum.h buffer.h camellia.h cast128.h \ cbc.h ccm.h cfb.h chacha.h chacha-poly1305.h ctr.h \ curve25519.h curve448.h des.h dsa.h dsa-compat.h eax.h \ diff --color -ruNp a/testsuite/balloon-test.c b/testsuite/balloon-test.c --- a/testsuite/balloon-test.c 1970-01-01 01:00:00.000000000 +0100 +++ b/testsuite/balloon-test.c 2022-08-18 16:29:24.926438931 +0200 @@ -0,0 +1,71 @@ +/* balloon-test.c + + Copyright (C) 2022 Zoltan Fridrich + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#include "testutils.h" +#include "balloon.h" +#include "nettle-internal.h" + +static inline void +test_balloon(size_t password_len, const char *password, + size_t salt_len, const char *salt, + unsigned s_cost, unsigned t_cost, + const struct nettle_hash *alg, const struct tstring *expected) +{ + uint8_t hash[NETTLE_MAX_HASH_DIGEST_SIZE]; + balloon(password_len, (const uint8_t *)password, + salt_len, (const uint8_t *)salt, + s_cost, t_cost, alg, hash); + + if (!MEMEQ(alg->digest_size, hash, expected->data)) { + fprintf(stderr, "test_balloon: result doesn't match the expectation:"); + fprintf(stderr, "\nOutput: "); + print_hex(alg->digest_size, hash); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(expected); + fprintf(stderr, "\n"); + FAIL(); + } +} + +void +test_main(void) +{ + test_balloon(8, "hunter42", 11, "examplesalt", 1024, 3, &nettle_sha256, + SHEX("716043dff777b44aa7b88dcbab12c078abecfac9d289c5b5195967aa63440dfb")); + test_balloon(0, "", 4, "salt", 3, 3, &nettle_sha256, + SHEX("5f02f8206f9cd212485c6bdf85527b698956701ad0852106f94b94ee94577378")); + test_balloon(8, "password", 0, "", 3, 3, &nettle_sha256, + SHEX("20aa99d7fe3f4df4bd98c655c5480ec98b143107a331fd491deda885c4d6a6cc")); + test_balloon(1, "", 1, "", 3, 3, &nettle_sha256, + SHEX("4fc7e302ffa29ae0eac31166cee7a552d1d71135f4e0da66486fb68a749b73a4")); + test_balloon(8, "password", 4, "salt", 1, 1, &nettle_sha256, + SHEX("eefda4a8a75b461fa389c1dcfaf3e9dfacbc26f81f22e6f280d15cc18c417545")); +} diff --color -ruNp a/testsuite/.gitignore b/testsuite/.gitignore --- a/testsuite/.gitignore 2022-08-03 15:22:54.246790154 +0200 +++ b/testsuite/.gitignore 2022-08-03 16:37:44.331951753 +0200 @@ -4,6 +4,7 @@ /aes-keywrap-test /arcfour-test /arctwo-test +/balloon-test /base16-test /base64-test /bignum-test diff --color -ruNp a/testsuite/Makefile.in b/testsuite/Makefile.in --- a/testsuite/Makefile.in 2022-08-03 15:22:54.246790154 +0200 +++ b/testsuite/Makefile.in 2022-08-03 16:39:17.725784157 +0200 @@ -11,7 +11,7 @@ PRE_CPPFLAGS = -I.. -I$(top_srcdir) PRE_LDFLAGS = -L.. TS_NETTLE_SOURCES = aes-test.c aes-keywrap-test.c arcfour-test.c arctwo-test.c \ - blowfish-test.c bcrypt-test.c cast128-test.c \ + balloon-test.c blowfish-test.c bcrypt-test.c cast128-test.c \ base16-test.c base64-test.c \ camellia-test.c chacha-test.c \ cnd-memcpy-test.c \
_______________________________________________ nettle-bugs mailing list -- [email protected] To unsubscribe send an email to [email protected]
