Hi Niels,

Thank you for another review. I have finalized the balloon.patch.
Changes made:

   - fixed formatting
   - increased return value of balloon_itch to include the "block" local
   variable at the beginning of scratch
   - wrappers moved to separate source files
   - tests expanded to test balloon_shaXXX functions

Sure, I can help with the docs, I will create a separate patch.
I think we can include scenarios (scratch == dst) in the docs.
After increasing the value of balloon_itch to include the block at the
beginning of scratch
there is absolutely no problem for scratch == dst, I have even changed
tests to use it like that.

I don't feel confident analysing and especially improving block_to_int()
modulus myself.
If the performance was a problem I could rework the function to use
mpz_mod() from the GMP library.

Kind regards,
Zoltan

On Mon, Sep 12, 2022 at 8:53 PM Niels Möller <ni...@lysator.liu.se> wrote:

> Zoltan Fridrich <zfrid...@redhat.com> writes:
>
> > I am sending you an updated patch. I have resolved all of the issues
> except
> > for the modulo.
> > Can you please take a look again?
>
> Thanks, looks in pretty pretty good shape now. Can you help out with
> docs? It can be a followup change, code can be submitted firwst.
>
> Docs should go in nettle.texinfo, probably in the "Key derivation
> functions" section, even if output size is fixed (unlike other key
> derivation functions which can also expand the key).
>
> > +/* Takes length bytes long big number stored
> > + * in little endian format and computes modulus
> > + */
> > +static size_t
> > +block_to_int(size_t length, const uint8_t *block, size_t mod)
> > +{
> > +    size_t i = length, r = 0;
> > +    while (i--) {
> > +        r = (r << 8) + block[i];
> > +        r %= mod;
> > +    }
> > +    return r;
> > +}
>
> This is quite clear. Might be interesting to run a profiler to see if it
> is in any way critical for performance. It requires that mod is a least
> 8 bits smaller than a size_t, but it seems the only call passes the hash
> digest size as the length, so that should be fine.
>
> > +void
> > +balloon(void *hash_ctx,
> > +        nettle_hash_update_func *update,
> > +        nettle_hash_digest_func *digest,
> > +        size_t digest_size, size_t s_cost, size_t t_cost,
> > +        size_t passwd_length, const uint8_t *passwd,
> > +        size_t salt_length, const uint8_t *salt,
> > +        uint8_t *buf, uint8_t *dst)
> > +{
> > +    uint8_t block[NETTLE_MAX_HASH_DIGEST_SIZE];
> > +    const size_t BS = digest_size;
>
> Would be good with an
>
>   assert (digest_size <= NETTLE_MAX_HASH_DIGEST_SIZE);
>
> Or maybe better: Increase return value of balloon_itch, and have it the
> block allocated at start or end of the passed in area. Something like
>
>   void
>   balloon(void *hash_ctx,
>           nettle_hash_update_func *update,
>           nettle_hash_digest_func *digest,
>           size_t digest_size, size_t s_cost, size_t t_cost,
>           size_t passwd_length, const uint8_t *passwd,
>           size_t salt_length, const uint8_t *salt,
>           uint8_t *scratch, uint8_t *dst)
>   {
>       const size_t BS = digest_size;
>       uint8_t *block = scratch;
>       uint8_t *buf = scratch + BS;
>       ...
>   }
>
>   size_t
>   balloon_itch(size_t digest_size, size_t s_cost)
>   {
>       return (s_cost + 1) * digest_size;
>   }
>
> > +    size_t i, j, k, cnt = 0;
> > +
> > +    hash(hash_ctx, update, digest, digest_size,
> > +         cnt++, passwd_length, passwd, salt_length, salt, buf);
> > +    for (i = 1; i < s_cost; ++i)
> > +        hash(hash_ctx, update, digest, digest_size,
> > +             cnt++, BS, buf + (i - 1) * BS, 0, NULL, buf + i * BS);
> > +
> > +    for (i = 0; i < t_cost; ++i) {
>
> Formatting nit: GNU style used in Nettle puts braces on their own line,
> indented halfway compared to the body of the block, like
>
>     for (i = 0; i < t_cost; ++i)
>       {
>         hash(hash_ctx, update, digest, digest_size, ...);
>         ...
>       }
>
> > +        for (j = 0; j < s_cost; ++j) {
> > +            hash(hash_ctx, update, digest, digest_size,
> > +                 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(hash_ctx, update, digest, digest_size, i, j,
> k, block);
> > +                hash(hash_ctx, update, digest, digest_size,
> > +                     cnt++, salt_length, salt, BS, block, block);
> > +                hash(hash_ctx, update, digest, digest_size,
> > +                     cnt++, BS, buf + j * BS,
> > +                     BS, buf + block_to_int(BS, block, s_cost) * BS,
> > +                     buf + j * BS);
> > +            }
> > +        }
> > +    }
> > +    memcpy(dst, buf + (s_cost - 1) * BS, BS);
>
> For the docs, consider if it should be documented that calling the
> function with dst == buf is allowed.
>
> > +}
> > +
> > +void
> > +balloon_sha1(size_t s_cost, size_t t_cost,
> > +             size_t passwd_length, const uint8_t *passwd,
> > +             size_t salt_length, const uint8_t *salt,
> > +             uint8_t *buf, uint8_t *dst)
> > +{
>
> One could consider moving these wrapper functions to separate source
> files, so that one can use, e.g, balloon_sha256, without getting a link
> dependency also on sha512. But not essential for the first version.
>
> > +/*
> > + * Test vectors are taken from:
> > + * <https://github.com/nachonavarro/balloon-hashing>
> > + * <
> https://github.com/RustCrypto/password-hashes/tree/master/balloon-hash>
> > + */
> > +void
> > +test_main(void)
> > +{
> > +    test_balloon(&nettle_sha256, 8, "hunter42", 11, "examplesalt",
> 1024, 3,
> > +
>  SHEX("716043dff777b44aa7b88dcbab12c078abecfac9d289c5b5195967aa63440dfb"));
> > +    test_balloon(&nettle_sha256, 0, "", 4, "salt", 3, 3,
> > +
>  SHEX("5f02f8206f9cd212485c6bdf85527b698956701ad0852106f94b94ee94577378"));
> > +    test_balloon(&nettle_sha256, 8, "password", 0, "", 3, 3,
> > +
>  SHEX("20aa99d7fe3f4df4bd98c655c5480ec98b143107a331fd491deda885c4d6a6cc"));
> > +    test_balloon(&nettle_sha256, 1, "", 1, "", 3, 3,
> > +
>  SHEX("4fc7e302ffa29ae0eac31166cee7a552d1d71135f4e0da66486fb68a749b73a4"));
> > +    test_balloon(&nettle_sha256, 8, "password", 4, "salt", 1, 1,
> > +
>  SHEX("eefda4a8a75b461fa389c1dcfaf3e9dfacbc26f81f22e6f280d15cc18c417545"));
> > +}
>
> Would be good with at least a single test for each of the balloon_shaXXX
> (even if test vectors verified with other implementations aren't
> available).
>
> Regards,
> /Niels
>
> --
> Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677.
> Internet email is subject to wholesale government surveillance.
>
>
diff --color -ruNp a/balloon.c b/balloon.c
--- a/balloon.c	1970-01-01 01:00:00.000000000 +0100
+++ b/balloon.c	2022-09-13 11:32:56.653133587 +0200
@@ -0,0 +1,146 @@
+/* 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/.
+*/
+
+/* For a description of the algorithm, see:
+ * Boneh, D., Corrigan-Gibbs, H., Schechter, S. (2017, May 12). Balloon Hashing:
+ * A Memory-Hard Function Providing Provable Protection Against Sequential Attacks.
+ * Retrieved Sep 1, 2022, from https://eprint.iacr.org/2016/027.pdf
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "balloon.h"
+#include "macros.h"
+
+#define DELTA 3
+
+static void
+hash(void *ctx,
+     nettle_hash_update_func *update,
+     nettle_hash_digest_func *digest,
+     size_t digest_size,
+     uint64_t cnt,
+     size_t a_len, const uint8_t *a,
+     size_t b_len, const uint8_t *b,
+     uint8_t *dst)
+{
+  uint8_t tmp[8];
+  LE_WRITE_UINT64(tmp, cnt);
+  update(ctx, sizeof(tmp), tmp);
+  update(ctx, a_len, a);
+  update(ctx, b_len, b);
+  digest(ctx, digest_size, dst);
+}
+
+static void
+hash_ints(void *ctx,
+          nettle_hash_update_func *update,
+          nettle_hash_digest_func *digest,
+          size_t digest_size,
+          uint64_t i, uint64_t j, uint64_t k,
+          uint8_t *dst)
+{
+  uint8_t tmp[24];
+  LE_WRITE_UINT64(tmp, i);
+  LE_WRITE_UINT64(tmp + 8, j);
+  LE_WRITE_UINT64(tmp + 16, k);
+  update(ctx, sizeof(tmp), tmp);
+  digest(ctx, digest_size, dst);
+}
+
+/* Takes length bytes long big number stored
+ * in little endian format and computes modulus
+ */
+static size_t
+block_to_int(size_t length, const uint8_t *block, size_t mod)
+{
+  size_t i = length, r = 0;
+  while (i--)
+    {
+      r = (r << 8) + block[i];
+      r %= mod;
+    }
+  return r;
+}
+
+void
+balloon(void *hash_ctx,
+        nettle_hash_update_func *update,
+        nettle_hash_digest_func *digest,
+        size_t digest_size, size_t s_cost, size_t t_cost,
+        size_t passwd_length, const uint8_t *passwd,
+        size_t salt_length, const uint8_t *salt,
+        uint8_t *scratch, uint8_t *dst)
+{
+  const size_t BS = digest_size;
+  uint8_t *block = scratch;
+  uint8_t *buf = scratch + BS;
+  size_t i, j, k, cnt = 0;
+
+  hash(hash_ctx, update, digest, digest_size,
+       cnt++, passwd_length, passwd, salt_length, salt, buf);
+  for (i = 1; i < s_cost; ++i)
+    hash(hash_ctx, update, digest, digest_size,
+         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(hash_ctx, update, digest, digest_size,
+               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(hash_ctx, update, digest, digest_size, i, j, k, block);
+              hash(hash_ctx, update, digest, digest_size,
+                   cnt++, salt_length, salt, BS, block, block);
+              hash(hash_ctx, update, digest, digest_size,
+                   cnt++, BS, buf + j * BS,
+                   BS, buf + block_to_int(BS, block, s_cost) * BS,
+                   buf + j * BS);
+            }
+        }
+    }
+  memcpy(dst, buf + (s_cost - 1) * BS, BS);
+}
+
+size_t
+balloon_itch(size_t digest_size, size_t s_cost)
+{
+  return (s_cost + 1) * digest_size;
+}
diff --color -ruNp a/balloon.h b/balloon.h
--- a/balloon.h	1970-01-01 01:00:00.000000000 +0100
+++ b/balloon.h	2022-09-13 12:11:09.897188336 +0200
@@ -0,0 +1,97 @@
+/* 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/.
+*/
+
+/* For a description of the algorithm, see:
+ * Boneh, D., Corrigan-Gibbs, H., Schechter, S. (2017, May 12). Balloon Hashing:
+ * A Memory-Hard Function Providing Provable Protection Against Sequential Attacks.
+ * Retrieved Sep 1, 2022, from https://eprint.iacr.org/2016/027.pdf
+ */
+
+#ifndef NETTLE_BALLOON_H_INCLUDED
+#define NETTLE_BALLOON_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define balloon nettle_balloon
+#define balloon_itch nettle_balloon_itch
+#define balloon_sha1 nettle_balloon_sha1
+#define balloon_sha256 nettle_balloon_sha256
+#define balloon_sha384 nettle_balloon_sha384
+#define balloon_sha512 nettle_balloon_sha512
+
+void
+balloon(void *hash_ctx,
+        nettle_hash_update_func *update,
+        nettle_hash_digest_func *digest,
+        size_t digest_size, size_t s_cost, size_t t_cost,
+        size_t passwd_length, const uint8_t *passwd,
+        size_t salt_length, const uint8_t *salt,
+        uint8_t *scratch, uint8_t *dst);
+
+size_t
+balloon_itch(size_t digest_size, size_t s_cost);
+
+void
+balloon_sha1(size_t s_cost, size_t t_cost,
+             size_t passwd_length, const uint8_t *passwd,
+             size_t salt_length, const uint8_t *salt,
+             uint8_t *scratch, uint8_t *dst);
+
+void
+balloon_sha256(size_t s_cost, size_t t_cost,
+               size_t passwd_length, const uint8_t *passwd,
+               size_t salt_length, const uint8_t *salt,
+               uint8_t *scratch, uint8_t *dst);
+
+void
+balloon_sha384(size_t s_cost, size_t t_cost,
+               size_t passwd_length, const uint8_t *passwd,
+               size_t salt_length, const uint8_t *salt,
+               uint8_t *scratch, uint8_t *dst);
+
+void
+balloon_sha512(size_t s_cost, size_t t_cost,
+               size_t passwd_length, const uint8_t *passwd,
+               size_t salt_length, const uint8_t *salt,
+               uint8_t *scratch, uint8_t *dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_BALLOON_H_INCLUDED */
diff --color -ruNp a/balloon-sha1.c b/balloon-sha1.c
--- a/balloon-sha1.c	1970-01-01 01:00:00.000000000 +0100
+++ b/balloon-sha1.c	2022-09-13 12:11:37.526742007 +0200
@@ -0,0 +1,54 @@
+/* balloon-sha1.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 "balloon.h"
+#include "sha1.h"
+
+void
+balloon_sha1(size_t s_cost, size_t t_cost,
+             size_t passwd_length, const uint8_t *passwd,
+             size_t salt_length, const uint8_t *salt,
+             uint8_t *scratch, uint8_t *dst)
+{
+  struct sha1_ctx ctx;
+  sha1_init(&ctx);
+  balloon(&ctx,
+          (nettle_hash_update_func*)sha1_update,
+          (nettle_hash_digest_func*)sha1_digest,
+          SHA1_DIGEST_SIZE, s_cost, t_cost,
+          passwd_length, passwd, salt_length, salt, scratch, dst);
+}
diff --color -ruNp a/balloon-sha256.c b/balloon-sha256.c
--- a/balloon-sha256.c	1970-01-01 01:00:00.000000000 +0100
+++ b/balloon-sha256.c	2022-09-13 12:11:55.801108209 +0200
@@ -0,0 +1,54 @@
+/* balloon-sha256.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 "balloon.h"
+#include "sha2.h"
+
+void
+balloon_sha256(size_t s_cost, size_t t_cost,
+               size_t passwd_length, const uint8_t *passwd,
+               size_t salt_length, const uint8_t *salt,
+               uint8_t *scratch, uint8_t *dst)
+{
+  struct sha256_ctx ctx;
+  sha256_init(&ctx);
+  balloon(&ctx,
+          (nettle_hash_update_func*)sha256_update,
+          (nettle_hash_digest_func*)sha256_digest,
+          SHA256_DIGEST_SIZE, s_cost, t_cost,
+          passwd_length, passwd, salt_length, salt, scratch, dst);
+}
diff --color -ruNp a/balloon-sha384.c b/balloon-sha384.c
--- a/balloon-sha384.c	1970-01-01 01:00:00.000000000 +0100
+++ b/balloon-sha384.c	2022-09-13 12:12:23.338660037 +0200
@@ -0,0 +1,54 @@
+/* balloon-sha384.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 "balloon.h"
+#include "sha2.h"
+
+void
+balloon_sha384(size_t s_cost, size_t t_cost,
+               size_t passwd_length, const uint8_t *passwd,
+               size_t salt_length, const uint8_t *salt,
+               uint8_t *scratch, uint8_t *dst)
+{
+  struct sha384_ctx ctx;
+  sha384_init(&ctx);
+  balloon(&ctx,
+          (nettle_hash_update_func*)sha384_update,
+          (nettle_hash_digest_func*)sha384_digest,
+          SHA384_DIGEST_SIZE, s_cost, t_cost,
+          passwd_length, passwd, salt_length, salt, scratch, dst);
+}
diff --color -ruNp a/balloon-sha512.c b/balloon-sha512.c
--- a/balloon-sha512.c	1970-01-01 01:00:00.000000000 +0100
+++ b/balloon-sha512.c	2022-09-13 12:12:10.241397580 +0200
@@ -0,0 +1,54 @@
+/* balloon-sha512.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 "balloon.h"
+#include "sha2.h"
+
+void
+balloon_sha512(size_t s_cost, size_t t_cost,
+               size_t passwd_length, const uint8_t *passwd,
+               size_t salt_length, const uint8_t *salt,
+               uint8_t *scratch, uint8_t *dst)
+{
+  struct sha512_ctx ctx;
+  sha512_init(&ctx);
+  balloon(&ctx,
+          (nettle_hash_update_func*)sha512_update,
+          (nettle_hash_digest_func*)sha512_digest,
+          SHA512_DIGEST_SIZE, s_cost, t_cost,
+          passwd_length, passwd, salt_length, salt, scratch, dst);
+}
diff --color -ruNp a/Makefile.in b/Makefile.in
--- a/Makefile.in	2022-08-03 15:22:54.207789385 +0200
+++ b/Makefile.in	2022-09-13 11:42:14.076343525 +0200
@@ -83,6 +83,8 @@ nettle_SOURCES = aes-decrypt-internal.c
 		 nist-keywrap.c \
 		 arcfour.c arcfour-crypt.c \
 		 arctwo.c arctwo-meta.c blowfish.c blowfish-bcrypt.c \
+		 balloon.c balloon-sha1.c balloon-sha256.c \
+		 balloon-sha384.c balloon-sha512.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 +220,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 blowfish.h balloon.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-09-13 12:13:04.051475885 +0200
@@ -0,0 +1,142 @@
+/* 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"
+
+static void
+test_balloon(const struct nettle_hash *alg,
+             size_t password_len, const char *password,
+             size_t salt_len, const char *salt,
+             unsigned s_cost, unsigned t_cost,
+             const struct tstring *expected)
+{
+  int fail = 0;
+  void *ctx = xalloc(alg->context_size);
+  uint8_t *buf = xalloc(balloon_itch(alg->digest_size, s_cost));
+
+  alg->init(ctx);
+  balloon(ctx, alg->update, alg->digest, alg->digest_size,
+          s_cost, t_cost, password_len, (const uint8_t *)password,
+          salt_len, (const uint8_t *)salt, buf, buf);
+
+  if (!MEMEQ(alg->digest_size, buf, expected->data))
+    {
+      fprintf(stderr, "test_balloon: result doesn't match the expectation:");
+      fprintf(stderr, "\nOutput: ");
+      print_hex(alg->digest_size, buf);
+      fprintf(stderr, "\nExpected:");
+      tstring_print_hex(expected);
+      fprintf(stderr, "\n");
+      fail = 1;
+    }
+
+  free(ctx);
+  free(buf);
+
+  if (fail)
+    FAIL();
+}
+
+static void
+test_balloon_sha(const struct nettle_hash *alg,
+                 size_t password_len, const char *password,
+                 size_t salt_len, const char *salt,
+                 unsigned s_cost, unsigned t_cost,
+                 const struct tstring *expected)
+{
+  int fail = 0;
+  uint8_t *buf = xalloc(balloon_itch(alg->digest_size, s_cost));
+
+  if (alg == &nettle_sha1)
+    balloon_sha1(s_cost, t_cost, password_len, (const uint8_t *)password,
+                 salt_len, (const uint8_t *)salt, buf, buf);
+  else if (alg == &nettle_sha256)
+    balloon_sha256(s_cost, t_cost, password_len, (const uint8_t *)password,
+                   salt_len, (const uint8_t *)salt, buf, buf);
+  else if (alg == &nettle_sha384)
+    balloon_sha384(s_cost, t_cost, password_len, (const uint8_t *)password,
+                   salt_len, (const uint8_t *)salt, buf, buf);
+  else if (alg == &nettle_sha512)
+    balloon_sha512(s_cost, t_cost, password_len, (const uint8_t *)password,
+                   salt_len, (const uint8_t *)salt, buf, buf);
+  else
+    {
+      fprintf(stderr, "test_balloon_sha: bad test\n");
+      fail = 1;
+    }
+
+  if (!fail && !MEMEQ(alg->digest_size, buf, expected->data))
+    {
+      fprintf(stderr, "test_balloon_sha: result doesn't match the expectation:");
+      fprintf(stderr, "\nOutput: ");
+      print_hex(alg->digest_size, buf);
+      fprintf(stderr, "\nExpected:");
+      tstring_print_hex(expected);
+      fprintf(stderr, "\n");
+      fail = 1;
+    }
+
+  free(buf);
+
+  if (fail)
+    FAIL();
+}
+
+/* Test vectors are taken from:
+ * <https://github.com/nachonavarro/balloon-hashing>
+ * <https://github.com/RustCrypto/password-hashes/tree/master/balloon-hash>
+ */
+void
+test_main(void)
+{
+  test_balloon(&nettle_sha256, 8, "hunter42", 11, "examplesalt", 1024, 3,
+               SHEX("716043dff777b44aa7b88dcbab12c078abecfac9d289c5b5195967aa63440dfb"));
+  test_balloon(&nettle_sha256, 0, "", 4, "salt", 3, 3,
+               SHEX("5f02f8206f9cd212485c6bdf85527b698956701ad0852106f94b94ee94577378"));
+  test_balloon(&nettle_sha256, 8, "password", 0, "", 3, 3,
+               SHEX("20aa99d7fe3f4df4bd98c655c5480ec98b143107a331fd491deda885c4d6a6cc"));
+  test_balloon(&nettle_sha256, 1, "", 1, "", 3, 3,
+               SHEX("4fc7e302ffa29ae0eac31166cee7a552d1d71135f4e0da66486fb68a749b73a4"));
+  test_balloon(&nettle_sha256, 8, "password", 4, "salt", 1, 1,
+               SHEX("eefda4a8a75b461fa389c1dcfaf3e9dfacbc26f81f22e6f280d15cc18c417545"));
+
+  test_balloon_sha(&nettle_sha1, 8, "password", 4, "salt", 3, 3,
+                   SHEX("99393c091fdd3136f85864099ec49a439dcacc21"));
+  test_balloon_sha(&nettle_sha256, 8, "password", 4, "salt", 3, 3,
+                   SHEX("a4df347f5a312e8b2b14c32164f61a81758c807f1bdcda44f4930e2b80ab2154"));
+  test_balloon_sha(&nettle_sha384, 8, "password", 4, "salt", 3, 3,
+                   SHEX("78da235f7d0f84aba98b50a432fa6c8f7f3ecb7ea0858cfb316c7e5356aae6c8"
+                        "d7e7b3924c54c4ed71a3d0d68cb0ad68"));
+  test_balloon_sha(&nettle_sha512, 8, "password", 4, "salt", 3, 3,
+                   SHEX("9baf289dfa42990f4b189d96d4ede0f2610ba71fb644169427829d696f6866d8"
+                        "7af41eb68f9e14fd4b1f1a7ce4832f1ed6117c16e8eae753f9e1d054a7c0a7eb"));
+}
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 -- nettle-bugs@lists.lysator.liu.se
To unsubscribe send an email to nettle-bugs-le...@lists.lysator.liu.se

Reply via email to