summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Makefile.in4
-rw-r--r--balloon-sha1.c55
-rw-r--r--balloon-sha256.c55
-rw-r--r--balloon-sha384.c55
-rw-r--r--balloon-sha512.c55
-rw-r--r--balloon.c149
-rw-r--r--balloon.h98
-rw-r--r--eccdata.c207
-rw-r--r--testsuite/.gitignore1
-rw-r--r--testsuite/Makefile.in2
-rw-r--r--testsuite/balloon-test.c135
12 files changed, 720 insertions, 102 deletions
diff --git a/ChangeLog b/ChangeLog
index 998a650a..6be196a6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2022-09-08 Niels Möller <nisse@lysator.liu.se>
+
+ * eccdata.c (string_toupper): New utility function.
+ (output_modulo): Move more of the per-modulo output here.
+ (output_curve): Remove corresponding code.
+
2022-08-31 Niels Möller <nisse@lysator.liu.se>
* bswap-internal.h (nettle_bswap64, nettle_bswap32)
diff --git a/Makefile.in b/Makefile.in
index 0f7bf4d6..b9e39581 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -83,6 +83,8 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.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 \
@@ -223,7 +225,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 --git a/balloon-sha1.c b/balloon-sha1.c
new file mode 100644
index 00000000..71c86e1d
--- /dev/null
+++ b/balloon-sha1.c
@@ -0,0 +1,55 @@
+/* balloon-sha1.c
+
+ Balloon password-hashing algorithm.
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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 --git a/balloon-sha256.c b/balloon-sha256.c
new file mode 100644
index 00000000..fe31a691
--- /dev/null
+++ b/balloon-sha256.c
@@ -0,0 +1,55 @@
+/* balloon-sha256.c
+
+ Balloon password-hashing algorithm.
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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 --git a/balloon-sha384.c b/balloon-sha384.c
new file mode 100644
index 00000000..68294496
--- /dev/null
+++ b/balloon-sha384.c
@@ -0,0 +1,55 @@
+/* balloon-sha384.c
+
+ Balloon password-hashing algorithm.
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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 --git a/balloon-sha512.c b/balloon-sha512.c
new file mode 100644
index 00000000..f19f8aa0
--- /dev/null
+++ b/balloon-sha512.c
@@ -0,0 +1,55 @@
+/* balloon-sha512.c
+
+ Balloon password-hashing algorithm.
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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 --git a/balloon.c b/balloon.c
new file mode 100644
index 00000000..c744160a
--- /dev/null
+++ b/balloon.c
@@ -0,0 +1,149 @@
+/* balloon.c
+
+ Balloon password-hashing algorithm.
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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);
+ if (a && a_len)
+ update(ctx, a_len, a);
+ if (b && b_len)
+ 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 --git a/balloon.h b/balloon.h
new file mode 100644
index 00000000..9c021925
--- /dev/null
+++ b/balloon.h
@@ -0,0 +1,98 @@
+/* balloon.h
+
+ Balloon password-hashing algorithm.
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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 --git a/eccdata.c b/eccdata.c
index 4459f5d2..0bb934ab 100644
--- a/eccdata.c
+++ b/eccdata.c
@@ -1153,138 +1153,145 @@ output_point (const struct ecc_curve *ecc,
}
static void
-output_modulo (const char *limb_name, const char *size_name, const mpz_t x,
- unsigned size, unsigned bits_per_limb)
+string_toupper (char *buf, size_t size, const char *s)
{
- mpz_t mod;
- unsigned bits;
-
- mpz_init (mod);
-
- mpz_setbit (mod, bits_per_limb * size);
- mpz_mod (mod, mod, x);
-
- bits = mpz_sizeinbase (mod, 2);
- output_bignum (limb_name, mod, size, bits_per_limb);
- printf ("#define %s %u\n", size_name,
- (bits + bits_per_limb - 1) / bits_per_limb);
-
- mpz_clear (mod);
+ size_t i;
+ for (i = 0; i < size; i++)
+ {
+ buf[i] = toupper ((int)s[i]);
+ if (!buf[i])
+ return;
+ }
+ fprintf (stderr, "string '%s' too large for buffer of size %u.\n",
+ s, (unsigned) size);
+ abort();
}
static void
-output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb)
+output_modulo (const char *name, const mpz_t x,
+ unsigned size, unsigned bits_per_limb)
{
- unsigned limb_size = (ecc->bit_size + bits_per_limb - 1)/bits_per_limb;
- unsigned i;
- unsigned qbits;
- int redc_limbs;
+ unsigned bit_size;
+ int shift;
+ char buf[20];
mpz_t t;
- mpz_t z;
- mpz_init (t);
- mpz_init (z);
+ snprintf (buf, sizeof (buf), "ecc_%s", name);
+ output_bignum (buf, x, size, bits_per_limb);
- printf ("/* For NULL. */\n#include <stddef.h>\n");
+ mpz_init (t);
- printf ("#define ECC_LIMB_SIZE %u\n", limb_size);
- printf ("#define ECC_PIPPENGER_K %u\n", ecc->pippenger_k);
- printf ("#define ECC_PIPPENGER_C %u\n", ecc->pippenger_c);
+ mpz_setbit (t, bits_per_limb * size);
+ mpz_mod (t, t, x);
- output_bignum ("ecc_p", ecc->p, limb_size, bits_per_limb);
- output_bignum ("ecc_b", ecc->b, limb_size, bits_per_limb);
- output_bignum ("ecc_q", ecc->q, limb_size, bits_per_limb);
+ snprintf (buf, sizeof (buf), "ecc_Bmod%s", name);
+ output_bignum (buf, t, size, bits_per_limb);
- output_modulo ("ecc_Bmodp", "ECC_BMODP_SIZE",
- ecc->p, limb_size, bits_per_limb);
- output_modulo ("ecc_Bmodq", "ECC_BMODQ_SIZE", ecc->q, limb_size, bits_per_limb);
+ string_toupper (buf, sizeof (buf), name);
+ printf ("#define ECC_BMOD%s_SIZE %u\n", buf,
+ (mpz_sizeinbase (t, 2) + bits_per_limb - 1) / bits_per_limb);
- qbits = mpz_sizeinbase (ecc->q, 2);
- if (qbits < ecc->bit_size)
+ bit_size = mpz_sizeinbase (x, 2);
+
+ shift = size * bits_per_limb - bit_size;
+ assert (shift >= 0);
+ if (shift > 0)
{
- /* for curve25519, with q = 2^k + q', with a much smaller q' */
- unsigned mbits;
- unsigned shift;
+ mpz_set_ui (t, 0);
+ mpz_setbit (t, size * bits_per_limb);
+ mpz_submul_ui (t, x, 2);
- /* Shift to align the one bit at B */
- shift = bits_per_limb * limb_size + 1 - qbits;
-
- mpz_set (t, ecc->q);
- mpz_clrbit (t, qbits-1);
- mbits = mpz_sizeinbase (t, 2);
+ snprintf (buf, sizeof (buf), "ecc_Bm2%s", name);
+ output_bignum (buf, t, size, bits_per_limb);
- /* The shifted value must be a limb smaller than q. */
- if (mbits + shift + bits_per_limb <= qbits)
+ if (bit_size == 253)
{
- /* q of the form 2^k + q', with q' a limb smaller */
- mpz_mul_2exp (t, t, shift);
- output_bignum ("ecc_mBmodq_shifted", t, limb_size, bits_per_limb);
- }
- }
+ /* For curve25519, with q = 2^k + q', with a much smaller q' */
+ unsigned mbits;
+ unsigned shift;
- if (ecc->bit_size < limb_size * bits_per_limb)
- {
- int shift;
+ /* Shift to align the one bit at B */
+ shift = bits_per_limb * size + 1 - bit_size;
- mpz_set_ui (t, 0);
- mpz_setbit (t, limb_size * bits_per_limb);
- mpz_submul_ui (t, ecc->p, 2);
- output_bignum ("ecc_Bm2p", t, limb_size, bits_per_limb);
+ mpz_set (t, x);
+ mpz_clrbit (t, bit_size-1);
+ mbits = mpz_sizeinbase (t, 2);
- mpz_set_ui (t, 0);
- mpz_setbit (t, ecc->bit_size);
- mpz_sub (t, t, ecc->p);
- output_bignum ("ecc_Bmodp_shifted", t, limb_size, bits_per_limb);
+ /* The shifted value must be a limb smaller than q. */
+ assert (mbits + shift + bits_per_limb <= bit_size);
- shift = limb_size * bits_per_limb - ecc->bit_size;
- assert (shift > 0);
+ /* q of the form 2^k + q', with q' a limb smaller */
+ mpz_mul_2exp (t, t, shift);
+ snprintf (buf, sizeof (buf), "ecc_mBmod%s_shifted", name);
- /* Check condition for reducing hi limbs. If s is the
- normalization shift and n is the bit size (so that s + n
- = limb_size * bite_per_limb), then we need
+ output_bignum (buf, t, size, bits_per_limb);
+ }
+ else
+ {
+ mpz_set_ui (t, 0);
+ mpz_setbit (t, bit_size);
+ mpz_sub (t, t, x);
- (2^n - 1) + (2^s - 1) (2^n - p) < 2p
+ snprintf (buf, sizeof (buf), "ecc_Bmod%s_shifted", name);
+ output_bignum (buf, t, size, bits_per_limb);
- or equivalently,
+ /* Check condition for reducing hi limbs. If s is the
+ normalization shift and n is the bit size (so that s + n
+ = limb_size * bits_per_limb), then we need
- 2^s (2^n - p) <= p
+ (2^n - 1) + (2^s - 1) (2^n - p) < 2p
- To a allow a carry limb to be added in at the same time,
- substitute s+1 for s.
- */
- /* FIXME: For ecdsa verify, we actually need the stricter
- inequality < 2 q. */
- mpz_mul_2exp (t, t, shift + 1);
- if (mpz_cmp (t, ecc->p) > 0)
- {
- fprintf (stderr, "Reduction condition failed for %u-bit curve.\n",
- ecc->bit_size);
- exit (EXIT_FAILURE);
+ or equivalently,
+
+ 2^s (2^n - p) <= p
+
+ To a allow a carry limb to be added in at the same time,
+ substitute s+1 for s.
+ */
+ /* FIXME: For ecdsa verify, we actually need the stricter
+ inequality < 2 q. */
+ mpz_mul_2exp (t, t, shift + 1);
+ if (mpz_cmp (t, x) > 0)
+ {
+ fprintf (stderr, "Reduction condition failed for %u-bit %s.\n",
+ bit_size, name);
+ exit (EXIT_FAILURE);
+ }
}
}
else
{
- printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n");
- printf ("#define ecc_Bm2p ecc_Bmodp\n");
+ printf ("#define ecc_Bm2%s ecc_Bmod%s\n", name, name);
+ printf ("#define ecc_Bmod%s_shifted ecc_Bmod%s\n", name, name);
}
- if (qbits < limb_size * bits_per_limb)
- {
- mpz_set_ui (t, 0);
- mpz_setbit (t, limb_size * bits_per_limb);
- mpz_submul_ui (t, ecc->q, 2);
- output_bignum ("ecc_Bm2q", t, limb_size, bits_per_limb);
+ mpz_clear (t);
+}
+
+static void
+output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb)
+{
+ unsigned limb_size = (ecc->bit_size + bits_per_limb - 1)/bits_per_limb;
+ unsigned i;
+ unsigned qbits;
+ int redc_limbs;
+ mpz_t t;
+ mpz_t z;
+
+ mpz_init (t);
+ mpz_init (z);
+
+ printf ("/* For NULL. */\n#include <stddef.h>\n");
+
+ printf ("#define ECC_LIMB_SIZE %u\n", limb_size);
+ printf ("#define ECC_PIPPENGER_K %u\n", ecc->pippenger_k);
+ printf ("#define ECC_PIPPENGER_C %u\n", ecc->pippenger_c);
+
+ output_modulo ("p", ecc->p, limb_size, bits_per_limb);
+ output_modulo ("q", ecc->q, limb_size, bits_per_limb);
+
+ output_bignum ("ecc_b", ecc->b, limb_size, bits_per_limb);
- mpz_set_ui (t, 0);
- mpz_setbit (t, qbits);
- mpz_sub (t, t, ecc->q);
- output_bignum ("ecc_Bmodq_shifted", t, limb_size, bits_per_limb);
- }
- else
- {
- printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n");
- printf ("#define ecc_Bm2q ecc_Bmodq\n");
- }
mpz_add_ui (t, ecc->p, 1);
mpz_fdiv_q_2exp (t, t, 1);
output_bignum ("ecc_pp1h", t, limb_size, bits_per_limb);
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 309464d6..8c91d1af 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -4,6 +4,7 @@
/aes-keywrap-test
/arcfour-test
/arctwo-test
+/balloon-test
/base16-test
/base64-test
/bignum-test
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 05442595..025ab72d 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -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 \
diff --git a/testsuite/balloon-test.c b/testsuite/balloon-test.c
new file mode 100644
index 00000000..ad63c7a0
--- /dev/null
+++ b/testsuite/balloon-test.c
@@ -0,0 +1,135 @@
+/* balloon-test.c
+
+ Copyright (C) 2022 Zoltan Fridrich
+ Copyright (C) 2022 Red Hat, Inc.
+
+ 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)
+{
+ 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();
+ }
+
+ free(ctx);
+ free(buf);
+}
+
+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)
+{
+ 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();
+ }
+
+ if (!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();
+ }
+
+ free(buf);
+}
+
+/* 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"));
+}