From: Daiki Ueno dueno@redhat.com
This series adds a variant of DSA/ECDSA signing functions that doesn't require random source to generate signature. The construction of the random parameter k is implemented according to RFC 6979, which will be part of FIPS 186-5: https://csrc.nist.gov/CSRC/media/Presentations/NIST-Status-Update-on-Ellipti...
The motivation behind this is to make it easier to check the DSA/ECDSA functionality in the circumstances where no proper random sources are available, e.g., in the libary self-tests at early boot stage.
Daiki Ueno (3): dsa: Add a function to find k deterministically ecdsa: Add support for deterministic signature generation dsa: Add support for deterministic signature generation
Makefile.in | 6 +- dsa-compute-k.c | 169 ++++++++++++++++++++++ dsa-compute-k.h | 63 ++++++++ dsa-sign-deterministic.c | 107 ++++++++++++++ dsa.h | 12 ++ ecdsa-sign-deterministic.c | 78 ++++++++++ ecdsa.h | 11 ++ testsuite/.gitignore | 2 + testsuite/.test-rules.make | 6 + testsuite/Makefile.in | 4 +- testsuite/dsa-compute-k-test.c | 85 +++++++++++ testsuite/dsa-test.c | 148 ++++++++++++++++++- testsuite/ecdsa-sign-deterministic-test.c | 164 +++++++++++++++++++++ 13 files changed, 851 insertions(+), 4 deletions(-) create mode 100644 dsa-compute-k.c create mode 100644 dsa-compute-k.h create mode 100644 dsa-sign-deterministic.c create mode 100644 ecdsa-sign-deterministic.c create mode 100644 testsuite/dsa-compute-k-test.c create mode 100644 testsuite/ecdsa-sign-deterministic-test.c
From: Daiki Ueno dueno@redhat.com
This adds the _dsa_compute_k function that generates DSA/ECDSA k value from the private key and the hashed message, according to RFC 6979.
Signed-off-by: Daiki Ueno dueno@redhat.com --- Makefile.in | 5 +- dsa-compute-k.c | 169 +++++++++++++++++++++++++++++++++ dsa-compute-k.h | 63 ++++++++++++ testsuite/.gitignore | 1 + testsuite/.test-rules.make | 3 + testsuite/Makefile.in | 3 +- testsuite/dsa-compute-k-test.c | 85 +++++++++++++++++ 7 files changed, 326 insertions(+), 3 deletions(-) create mode 100644 dsa-compute-k.c create mode 100644 dsa-compute-k.h create mode 100644 testsuite/dsa-compute-k-test.c
diff --git a/Makefile.in b/Makefile.in index a6b8ffd6..b0adcb3c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -186,7 +186,8 @@ hogweed_SOURCES = sexp.c sexp-format.c \ eddsa-compress.c eddsa-decompress.c eddsa-expand.c \ eddsa-hash.c eddsa-pubkey.c eddsa-sign.c eddsa-verify.c \ ed25519-sha512-pubkey.c \ - ed25519-sha512-sign.c ed25519-sha512-verify.c + ed25519-sha512-sign.c ed25519-sha512-verify.c \ + dsa-compute-k.c
OPT_SOURCES = fat-x86_64.c fat-arm.c mini-gmp.c
@@ -236,7 +237,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \ ctr-internal.h chacha-internal.h sha3-internal.h \ salsa20-internal.h umac-internal.h hogweed-internal.h \ rsa-internal.h pkcs1-internal.h dsa-internal.h eddsa-internal.h \ - gmp-glue.h ecc-internal.h fat-setup.h \ + gmp-glue.h ecc-internal.h fat-setup.h dsa-compute-k.h \ mini-gmp.h asm.m4 \ nettle.texinfo nettle.info nettle.html nettle.pdf sha-example.c
diff --git a/dsa-compute-k.c b/dsa-compute-k.c new file mode 100644 index 00000000..ba9b50df --- /dev/null +++ b/dsa-compute-k.c @@ -0,0 +1,169 @@ +/* dsa-compute-k.c + + Deterministically find k value for ECDSA/DSA (RFC-6979). + + Copyright (C) 2019 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 "dsa-compute-k.h" + +#include "gmp-glue.h" +#include "nettle-internal.h" +#include <string.h> + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) < (y) ? (y) : (x)) + +void +_dsa_compute_k (mp_limb_t *k, + mp_size_t qn, + const mp_limb_t *q, + const mp_limb_t *x, + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_length, + const uint8_t *digest_message) +{ + TMP_DECL(V, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_DECL(K, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_GMP_DECL(xp, uint8_t); + TMP_GMP_DECL(hp, uint8_t); + TMP_GMP_DECL(tp, uint8_t); + TMP_GMP_DECL(h, mp_limb_t); + mp_size_t hn = (digest_length + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t); + mp_bitcnt_t q_bits = mpn_sizeinbase (q, qn, 2); + mp_bitcnt_t h_bits; + mp_bitcnt_t k_bits; + size_t nbytes = (q_bits + 7) / 8; + const uint8_t c0 = 0x00; + const uint8_t c1 = 0x01; + + TMP_ALLOC(V, digest_length); + TMP_ALLOC(K, digest_length); + TMP_GMP_ALLOC(xp, nbytes); + TMP_GMP_ALLOC(hp, nbytes); + TMP_GMP_ALLOC(tp, nbytes); + TMP_GMP_ALLOC(h, MAX(hn, qn) * sizeof(mp_limb_t)); + + /* int2octets(x) */ + mpn_get_base256 (xp, nbytes, x, qn); + + /* bits2octets(h) */ + mpn_set_base256 (h, hn, digest_message, digest_length); + if (hn > qn) + mpn_copyi (h, &h[hn - qn], qn); + else if (hn < qn) + mpn_zero (&h[hn], qn - hn); + if (h[qn - 1] > 0) + { + h_bits = ((mpn_sizeinbase (h, qn, 2) + 7) / 8) * 8; + if (h_bits > q_bits) + mpn_rshift (h, h, qn, h_bits - q_bits); + } + cnd_sub_n (mpn_cmp (h, q, qn) > 0, h, q, qn); + mpn_get_base256 (hp, nbytes, h, qn); + + /* Step b */ + memset (V, c1, digest_length); + + /* Step c */ + memset (K, c0, digest_length); + set_key (mac_ctx, digest_length, K); + + /* Step d */ + update (mac_ctx, digest_length, V); + update (mac_ctx, 1, &c0); + update (mac_ctx, nbytes, xp); + update (mac_ctx, nbytes, hp); + digest (mac_ctx, digest_length, K); + set_key (mac_ctx, digest_length, K); + + /* Step e */ + update (mac_ctx, digest_length, V); + digest (mac_ctx, digest_length, V); + + /* Step f */ + update (mac_ctx, digest_length, V); + update (mac_ctx, 1, &c1); + update (mac_ctx, nbytes, xp); + update (mac_ctx, nbytes, hp); + digest (mac_ctx, digest_length, K); + set_key (mac_ctx, digest_length, K); + + /* Step g */ + update (mac_ctx, digest_length, V); + digest (mac_ctx, digest_length, V); + + /* Step h */ + for (;;) + { + /* Step 1 */ + size_t tlen = 0; + + /* Step 2 */ + while (tlen < nbytes) + { + size_t remaining = MIN(nbytes - tlen, digest_length); + update (mac_ctx, digest_length, V); + digest (mac_ctx, digest_length, V); + memcpy (&tp[tlen], V, remaining); + tlen += remaining; + } + + /* Step 3 */ + mpn_set_base256 (k, qn, tp, tlen); + if (k[qn - 1] > 0) + { + k_bits = ((mpn_sizeinbase (k, qn, 2) + 7) / 8) * 8; + if (k_bits > q_bits) + mpn_rshift (k, k, qn, k_bits - q_bits); + } + /* Check if k is in [1,q-1] */ + if (!mpn_zero_p (k, qn) && mpn_cmp (k, q, qn) < 0) + break; + + update (mac_ctx, digest_length, V); + update (mac_ctx, 1, &c0); + digest (mac_ctx, digest_length, K); + set_key (mac_ctx, digest_length, K); + update (mac_ctx, digest_length, V); + digest (mac_ctx, digest_length, V); + } + + TMP_GMP_FREE(xp); + TMP_GMP_FREE(hp); + TMP_GMP_FREE(tp); + TMP_GMP_FREE(h); +} diff --git a/dsa-compute-k.h b/dsa-compute-k.h new file mode 100644 index 00000000..3433e2fb --- /dev/null +++ b/dsa-compute-k.h @@ -0,0 +1,63 @@ +/* dsa-compute-k.h + + Deterministically find k value for ECDSA/DSA (RFC-6979). + + Copyright (C) 2019 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/. +*/ + +#ifndef NETTLE_DSA_COMPUTE_K_H_INCLUDED +#define NETTLE_DSA_COMPUTE_K_H_INCLUDED + +#include "nettle-types.h" +#include "bignum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Namespace mangling */ +#define _dsa_compute_k _nettle_dsa_compute_k + +void +_dsa_compute_k (mp_limb_t *k, + mp_size_t qn, + const mp_limb_t *q, + const mp_limb_t *x, + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_length, + const uint8_t *digest_message); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_DSA_COMPUTE_K_H_INCLUDED */ diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 4d680cd1..6adde730 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -22,6 +22,7 @@ /des-test /des3-test /dlopen-test +/dsa-compute-k-test /dsa-keygen-test /dsa-test /eax-test diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make index ab22da23..c3a5bb85 100644 --- a/testsuite/.test-rules.make +++ b/testsuite/.test-rules.make @@ -277,6 +277,9 @@ eddsa-verify-test$(EXEEXT): eddsa-verify-test.$(OBJEXT) ed25519-test$(EXEEXT): ed25519-test.$(OBJEXT) $(LINK) ed25519-test.$(OBJEXT) $(TEST_OBJS) -o ed25519-test$(EXEEXT)
+dsa-compute-k-test$(EXEEXT): dsa-compute-k-test.$(OBJEXT) + $(LINK) dsa-compute-k-test.$(OBJEXT) $(TEST_OBJS) -o dsa-compute-k-test$(EXEEXT) + sha1-huge-test$(EXEEXT): sha1-huge-test.$(OBJEXT) $(LINK) sha1-huge-test.$(OBJEXT) $(TEST_OBJS) -o sha1-huge-test$(EXEEXT)
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 9a1fe209..3bc22057 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -52,7 +52,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \ ecdsa-sign-test.c ecdsa-verify-test.c \ ecdsa-keygen-test.c ecdh-test.c \ eddsa-compress-test.c eddsa-sign-test.c \ - eddsa-verify-test.c ed25519-test.c + eddsa-verify-test.c ed25519-test.c \ + dsa-compute-k-test.c
TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES) CXX_SOURCES = cxx-test.cxx diff --git a/testsuite/dsa-compute-k-test.c b/testsuite/dsa-compute-k-test.c new file mode 100644 index 00000000..07b0a06e --- /dev/null +++ b/testsuite/dsa-compute-k-test.c @@ -0,0 +1,85 @@ +#include "testutils.h" +#include "dsa-compute-k.h" +#include "hmac.h" + +static void +test_dsa_compute_k(const char *sq, + /* Private key */ + const char *sx, + /* HMAC */ + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + /* Hash */ + const struct tstring *h, + /* Expected k */ + const char *sk) +{ + mpz_t k; + mpz_t q; + mpz_t x; + mpz_t e; + + mpz_init (k); + mpz_init_set_str (q, sq, 16); + mpz_init_set_str (x, sx, 16); + mpz_init_set_str (e, sk, 16); + + _dsa_compute_k (mpz_limbs_write (k, mpz_size (q)), + mpz_size (q), mpz_limbs_read (q), mpz_limbs_read (x), + mac_ctx, set_key, update, digest, + h->length, h->data); + + mpz_limbs_finish (k, mpz_size (q)); + + if (mpz_cmp (e, k) != 0) + { + fprintf (stderr, "k = "); + mpz_out_str (stderr, 16, k); + fprintf (stderr, "\n"); + fprintf (stderr, "e = "); + mpz_out_str (stderr, 16, e); + fprintf (stderr, "\n"); + abort (); + } + + mpz_clear (q); + mpz_clear (x); + mpz_clear (k); + mpz_clear (e); +} + +void +test_main (void) +{ + struct hmac_sha256_ctx hmac; + struct sha256_ctx hash; + uint8_t digest[SHA256_DIGEST_SIZE]; + + sha256_init (&hash); + sha256_update (&hash, 6, (const uint8_t *)"sample"); + sha256_digest (&hash, sizeof(digest), digest); + + /* Test vectors from RFC 6979 */ + test_dsa_compute_k ("996f967f6c8e388d9e28d01e205fba957a5698b1", + "411602cb19a6ccc34494d79d98ef1e7ed5af25f7", + &hmac, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), + "519ba0546d0c39202a7d34d7dfa5e760b318bcfb"); + + test_dsa_compute_k ("f2c3119374ce76c9356990b465374a17f23f9ed3" + "5089bd969f61c6dde9998c1f", + "69c7548c21d0dfea6b9a51c9ead4e27c33d3b3f1" + "80316e5bcab92c933f0e4dbc", + &hmac, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), + "8926a27c40484216f052f4427cfd5647338b7b39" + "39bc6573af4333569d597c52"); +}
From: Daiki Ueno dueno@redhat.com
This adds the ecdsa_sign_deterministic function that calculates signature without requiring entropy source. Instead, it uses the deterministic construction described in RFC 6979, through _dsa_compute_k.
Signed-off-by: Daiki Ueno dueno@redhat.com --- Makefile.in | 2 +- ecdsa-sign-deterministic.c | 78 ++++++++++ ecdsa.h | 11 ++ testsuite/.gitignore | 1 + testsuite/.test-rules.make | 3 + testsuite/Makefile.in | 3 +- testsuite/ecdsa-sign-deterministic-test.c | 164 ++++++++++++++++++++++ 7 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 ecdsa-sign-deterministic.c create mode 100644 testsuite/ecdsa-sign-deterministic-test.c
diff --git a/Makefile.in b/Makefile.in index b0adcb3c..5f77b98d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -187,7 +187,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \ eddsa-hash.c eddsa-pubkey.c eddsa-sign.c eddsa-verify.c \ ed25519-sha512-pubkey.c \ ed25519-sha512-sign.c ed25519-sha512-verify.c \ - dsa-compute-k.c + dsa-compute-k.c ecdsa-sign-deterministic.c
OPT_SOURCES = fat-x86_64.c fat-arm.c mini-gmp.c
diff --git a/ecdsa-sign-deterministic.c b/ecdsa-sign-deterministic.c new file mode 100644 index 00000000..dd5b88d9 --- /dev/null +++ b/ecdsa-sign-deterministic.c @@ -0,0 +1,78 @@ +/* ecdsa-sign-deterministic.c + + Copyright (C) 2013 Niels Möller + Copyright (C) 2019 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/. +*/ + +/* Development of Nettle's ECC support was funded by the .SE Internet Fund. */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <stdlib.h> + +#include "ecdsa.h" +#include "ecc-internal.h" +#include "nettle-internal.h" +#include "dsa-compute-k.h" + +void +ecdsa_sign_deterministic (const struct ecc_scalar *key, + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_length, + const uint8_t *digest_message, + struct dsa_signature *signature) +{ + /* At most 936 bytes. */ + TMP_DECL(k, mp_limb_t, ECC_MAX_SIZE + ECC_ECDSA_SIGN_ITCH (ECC_MAX_SIZE)); + mp_limb_t size = key->ecc->p.size; + mp_limb_t *rp = mpz_limbs_write (signature->r, size); + mp_limb_t *sp = mpz_limbs_write (signature->s, size); + + TMP_ALLOC (k, size + ECC_ECDSA_SIGN_ITCH (size)); + + /* Timing reveals the number of rounds through this loop, but the + timing is still independent of the secret k finally used. */ + do + { + _dsa_compute_k (k, key->ecc->q.size, key->ecc->q.m, key->p, + mac_ctx, set_key, update, digest, + digest_length, digest_message); + ecc_ecdsa_sign (key->ecc, key->p, k, digest_length, digest_message, + rp, sp, k + size); + mpz_limbs_finish (signature->r, size); + mpz_limbs_finish (signature->s, size); + } + while (mpz_sgn (signature->r) == 0 || mpz_sgn (signature->s) == 0); +} diff --git a/ecdsa.h b/ecdsa.h index 693aca8b..7d590367 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -43,6 +43,7 @@ extern "C" {
/* Name mangling */ #define ecdsa_sign nettle_ecdsa_sign +#define ecdsa_sign_deterministic nettle_ecdsa_sign_deterministic #define ecdsa_verify nettle_ecdsa_verify #define ecdsa_generate_keypair nettle_ecdsa_generate_keypair #define ecc_ecdsa_sign nettle_ecc_ecdsa_sign @@ -61,6 +62,16 @@ ecdsa_sign (const struct ecc_scalar *key, const uint8_t *digest, struct dsa_signature *signature);
+void +ecdsa_sign_deterministic (const struct ecc_scalar *key, + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_length, + const uint8_t *digest_message, + struct dsa_signature *signature); + int ecdsa_verify (const struct ecc_point *pub, size_t length, const uint8_t *digest, diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 6adde730..10fbbbc0 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -36,6 +36,7 @@ /ecc-sqrt-test /ecdh-test /ecdsa-keygen-test +/ecdsa-sign-deterministic-test /ecdsa-sign-test /ecdsa-verify-test /ed25519-test diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make index c3a5bb85..463c10d0 100644 --- a/testsuite/.test-rules.make +++ b/testsuite/.test-rules.make @@ -280,6 +280,9 @@ ed25519-test$(EXEEXT): ed25519-test.$(OBJEXT) dsa-compute-k-test$(EXEEXT): dsa-compute-k-test.$(OBJEXT) $(LINK) dsa-compute-k-test.$(OBJEXT) $(TEST_OBJS) -o dsa-compute-k-test$(EXEEXT)
+ecdsa-sign-deterministic-test$(EXEEXT): ecdsa-sign-deterministic-test.$(OBJEXT) + $(LINK) ecdsa-sign-deterministic-test.$(OBJEXT) $(TEST_OBJS) -o ecdsa-sign-deterministic-test$(EXEEXT) + sha1-huge-test$(EXEEXT): sha1-huge-test.$(OBJEXT) $(LINK) sha1-huge-test.$(OBJEXT) $(TEST_OBJS) -o sha1-huge-test$(EXEEXT)
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 3bc22057..83807d42 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -53,7 +53,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \ ecdsa-keygen-test.c ecdh-test.c \ eddsa-compress-test.c eddsa-sign-test.c \ eddsa-verify-test.c ed25519-test.c \ - dsa-compute-k-test.c + dsa-compute-k-test.c \ + ecdsa-sign-deterministic-test.c
TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES) CXX_SOURCES = cxx-test.cxx diff --git a/testsuite/ecdsa-sign-deterministic-test.c b/testsuite/ecdsa-sign-deterministic-test.c new file mode 100644 index 00000000..37b82217 --- /dev/null +++ b/testsuite/ecdsa-sign-deterministic-test.c @@ -0,0 +1,164 @@ +#include "testutils.h" +#include "hmac.h" +#include "nettle-internal.h" + +static void +test_ecdsa (const struct ecc_curve *ecc, + /* Private key */ + const char *sz, + /* HMAC */ + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + /* Hash */ + const struct tstring *h, + /* Expected signature */ + const char *r, const char *s) +{ + struct ecc_scalar key; + struct dsa_signature ref; + struct dsa_signature signature; + mpz_t z; + + dsa_signature_init (&ref); + dsa_signature_init (&signature); + + mpz_init_set_str (z, sz, 16); + + ecc_scalar_init (&key, ecc); + ecc_scalar_set (&key, z); + + ecdsa_sign_deterministic (&key, + mac_ctx, set_key, update, digest, + h->length, h->data, &signature); + + mpz_set_str (ref.r, r, 16); + mpz_set_str (ref.s, s, 16); + + if (mpz_limbs_cmp (ref.r, mpz_limbs_read (signature.r), ecc->p.size) != 0 + || mpz_limbs_cmp (ref.s, mpz_limbs_read (signature.s), ecc->p.size) != 0) + { + fprintf (stderr, "_ecdsa_sign failed, bit_size = %u\n", ecc->p.bit_size); + fprintf (stderr, "r = "); + write_mpn (stderr, 16, mpz_limbs_read (signature.r), ecc->p.size); + fprintf (stderr, "\ns = "); + write_mpn (stderr, 16, mpz_limbs_read (signature.s), ecc->p.size); + fprintf (stderr, "\nref.r = "); + mpz_out_str (stderr, 16, ref.r); + fprintf (stderr, "\nref.s = "); + mpz_out_str (stderr, 16, ref.s); + fprintf (stderr, "\n"); + abort(); + } + + dsa_signature_clear (&ref); + dsa_signature_clear (&signature); + ecc_scalar_clear (&key); + mpz_clear (z); +} + +void +test_main (void) +{ + struct hmac_sha256_ctx hmac_sha256; + struct sha256_ctx hash_sha256; + uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE]; + + sha256_init (&hash_sha256); + sha256_update (&hash_sha256, 6, (const uint8_t *)"sample"); + sha256_digest (&hash_sha256, SHA256_DIGEST_SIZE, digest); + + test_ecdsa (&_nettle_secp_192r1, + "6fab034934e4c0fc9ae67f5b5659a9d7" + "d1fefd187ee09fd4", /* z */ + + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + + "4b0b8ce98a92866a2820e20aa6b75b56" + "382e0f9bfd5ecb55", /* r */ + + "ccdb006926ea9565cbadc840829d8c38" + "4e06de1f1e381b85"); /* s */ + + test_ecdsa (&_nettle_secp_224r1, + "f220266e1105bfe3083e03ec7a3a6546" + "51f45e37167e88600bf257c1", /* z */ + + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + + "61aa3da010e8e8406c656bc477a7a718" + "9895e7e840cdfe8ff42307ba", /* r */ + + "bc814050dab5d23770879494f9e0a680" + "dc1af7161991bde692b10101"); /* s */ + + test_ecdsa (&_nettle_secp_256r1, + "c9afa9d845ba75166b5c215767b1d693" + "4e50c3db36e89b127b8a622b120f6721", /* z */ + + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + + "efd48b2aacb6a8fd1140dd9cd45e81d6" + "9d2c877b56aaf991c34d0ea84eaf3716", /* r */ + + "f7cb1c942d657c41d436c7a1b6e29f65" + "f3e900dbb9aff4064dc4ab2f843acda8"); /* s */ + + test_ecdsa (&_nettle_secp_384r1, + "6b9d3dad2e1b8c1c05b19875b6659f4d" + "e23c3b667bf297ba9aa47740787137d8" + "96d5724e4c70a825f872c9ea60d2edf5", /* z */ + + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + + "21b13d1e013c7fa1392d03c5f99af8b3" + "0c570c6f98d4ea8e354b63a21d3daa33" + "bde1e888e63355d92fa2b3c36d8fb2cd", /* r */ + + "f3aa443fb107745bf4bd77cb38916746" + "32068a10ca67e3d45db2266fa7d1feeb" + "efdc63eccd1ac42ec0cb8668a4fa0ab0"); /* s */ + + test_ecdsa (&_nettle_secp_521r1, + "0fad06daa62ba3b25d2fb40133da7572" + "05de67f5bb0018fee8c86e1b68c7e75c" + "aa896eb32f1f47c70855836a6d16fcc1" + "466f6d8fbec67db89ec0c08b0e996b83" + "538", /* z */ + + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + + "1511bb4d675114fe266fc4372b87682b" + "aecc01d3cc62cf2303c92b3526012659" + "d16876e25c7c1e57648f23b73564d67f" + "61c6f14d527d54972810421e7d87589e" + "1a7", /* r */ + + "04a171143a83163d6df460aaf6152269" + "5f207a58b95c0644d87e52aa1a347916" + "e4f7a72930b1bc06dbe22ce3f58264af" + "d23704cbb63b29b931f7de6c9d949a7e" + "cfc"); /* s */ + +}
From: Daiki Ueno dueno@redhat.com
This adds the ecdsa_sign_deterministic function that calculates signature without requiring entropy source. Instead, it uses the deterministic construction described in RFC 6979, through _dsa_compute_k.
Signed-off-by: Daiki Ueno dueno@redhat.com --- Makefile.in | 3 +- dsa-sign-deterministic.c | 107 ++++++++++++++++++++++++++++ dsa.h | 12 ++++ testsuite/dsa-test.c | 148 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 dsa-sign-deterministic.c
diff --git a/Makefile.in b/Makefile.in index 5f77b98d..856f9d9e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -187,7 +187,8 @@ hogweed_SOURCES = sexp.c sexp-format.c \ eddsa-hash.c eddsa-pubkey.c eddsa-sign.c eddsa-verify.c \ ed25519-sha512-pubkey.c \ ed25519-sha512-sign.c ed25519-sha512-verify.c \ - dsa-compute-k.c ecdsa-sign-deterministic.c + dsa-compute-k.c ecdsa-sign-deterministic.c \ + dsa-sign-deterministic.c
OPT_SOURCES = fat-x86_64.c fat-arm.c mini-gmp.c
diff --git a/dsa-sign-deterministic.c b/dsa-sign-deterministic.c new file mode 100644 index 00000000..8c75b80f --- /dev/null +++ b/dsa-sign-deterministic.c @@ -0,0 +1,107 @@ +/* dsa-sign-deterministic.c + + Copyright (C) 2002, 2010 Niels Möller + Copyright (C) 2019 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 <assert.h> +#include <stdlib.h> + +#include "dsa.h" +#include "dsa-internal.h" +#include "dsa-compute-k.h" + +#include "bignum.h" + + +int +dsa_sign_deterministic (const struct dsa_params *params, + const mpz_t x, + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_length, + const uint8_t *digest_message, + struct dsa_signature *signature) +{ + mpz_t k; + mpz_t h; + mpz_t tmp; + int res; + + /* Check that p is odd, so that invalid keys don't result in a crash + inside mpz_powm_sec. */ + if (mpz_even_p (params->p)) + return 0; + + /* Select k, 0<k<q, deterministically */ + mpz_init(k); + _dsa_compute_k (mpz_limbs_write (k, mpz_size (params->q)), + mpz_size (params->q), + mpz_limbs_read (params->q), + mpz_limbs_read (x), + mac_ctx, set_key, update, digest, + digest_length, digest_message); + mpz_limbs_finish (k, mpz_size (params->q)); + + /* Compute r = (g^k (mod p)) (mod q) */ + mpz_init (tmp); + mpz_powm_sec(tmp, params->g, k, params->p); + mpz_fdiv_r(signature->r, tmp, params->q); + + /* Compute hash */ + mpz_init(h); + _dsa_hash (h, mpz_sizeinbase(params->q, 2), digest_length, digest_message); + + /* Compute k^-1 (mod q) */ + if (mpz_invert(k, k, params->q)) + { + /* Compute signature s = k^-1 (h + xr) (mod q) */ + mpz_mul(tmp, signature->r, x); + mpz_fdiv_r(tmp, tmp, params->q); + mpz_add(tmp, tmp, h); + mpz_mul(tmp, tmp, k); + mpz_fdiv_r(signature->s, tmp, params->q); + res = 1; + } + else + /* What do we do now? The key is invalid. */ + res = 0; + + mpz_clear(k); + mpz_clear(h); + mpz_clear(tmp); + + return res; +} diff --git a/dsa.h b/dsa.h index 553ef327..fddaea9d 100644 --- a/dsa.h +++ b/dsa.h @@ -47,6 +47,7 @@ extern "C" { #define dsa_signature_init nettle_dsa_signature_init #define dsa_signature_clear nettle_dsa_signature_clear #define dsa_sign nettle_dsa_sign +#define dsa_sign_deterministic nettle_dsa_sign_deterministic #define dsa_verify nettle_dsa_verify #define dsa_generate_params nettle_dsa_generate_params #define dsa_generate_keypair nettle_dsa_generate_keypair @@ -109,6 +110,17 @@ dsa_sign(const struct dsa_params *params, const uint8_t *digest, struct dsa_signature *signature);
+int +dsa_sign_deterministic (const struct dsa_params *params, + const mpz_t x, + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_length, + const uint8_t *digest_message, + struct dsa_signature *signature); + int dsa_verify(const struct dsa_params *params, const mpz_t y, diff --git a/testsuite/dsa-test.c b/testsuite/dsa-test.c index 9a80c967..dbc8d063 100644 --- a/testsuite/dsa-test.c +++ b/testsuite/dsa-test.c @@ -1,4 +1,57 @@ #include "testutils.h" +#include "hmac.h" +#include "nettle-internal.h" + +static void +test_dsa_sign_deterministic(const struct dsa_params *params, + /* Private key */ + const char *sz, + /* HMAC */ + void *mac_ctx, + nettle_hash_update_func *set_key, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + /* Hash */ + const struct tstring *h, + /* Expected signature */ + const char *r, const char *s) +{ + struct dsa_signature ref; + struct dsa_signature signature; + mpz_t z; + + dsa_signature_init (&ref); + dsa_signature_init(&signature); + + mpz_init_set_str (z, sz, 16); + + ASSERT (dsa_sign_deterministic (params, z, + mac_ctx, set_key, update, digest, + h->length, h->data, &signature)); + + mpz_set_str (ref.r, r, 16); + mpz_set_str (ref.s, s, 16); + + if (mpz_cmp (signature.r, ref.r) != 0 + || mpz_cmp (signature.s, ref.s) != 0) + { + fprintf (stderr, "_dsa_sign failed\n"); + fprintf (stderr, "r = "); + mpz_out_str (stderr, 16, signature.r); + fprintf (stderr, "\ns = "); + mpz_out_str (stderr, 16, signature.s); + fprintf (stderr, "\nref.r = "); + mpz_out_str (stderr, 16, ref.r); + fprintf (stderr, "\nref.s = "); + mpz_out_str (stderr, 16, ref.s); + fprintf (stderr, "\n"); + abort(); + } + + dsa_signature_clear (&ref); + dsa_signature_clear (&signature); + mpz_clear (z); +}
void test_main(void) @@ -7,6 +60,13 @@ test_main(void) struct dsa_private_key key; struct dsa_signature signature; struct dsa_params *params = (struct dsa_params *) &pub; + struct hmac_sha256_ctx hmac_sha256; + struct sha256_ctx hash_sha256; + uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE]; + + sha256_init (&hash_sha256); + sha256_update (&hash_sha256, 6, (const uint8_t *)"sample"); + sha256_digest (&hash_sha256, SHA256_DIGEST_SIZE, digest);
dsa_public_key_init(&pub); dsa_private_key_init(&key); @@ -877,7 +937,93 @@ test_main(void) "bb7441c122f1dc2f9d0b0bc07f26ba29a35cdf0da846a9d8" "eab405cbf8c8e77f"), &signature); - + + /* Test vectors from RFC 6979 */ + mpz_set_str(pub.p, + "86f5ca03dcfeb225063ff830a0c769b9dd9d6153ad91d7ce" + "27f787c43278b447e6533b86b18bed6e8a48b784a14c252c" + "5be0dbf60b86d6385bd2f12fb763ed8873abfd3f5ba2e0a8" + "c0a59082eac056935e529daf7c610467899c77adedfc846c" + "881870b7b19b2b58f9be0521a17002e3bdd6b86685ee90b3" + "d9a1b02b782b1779", 16); + mpz_set_str(pub.q, + "996f967f6c8e388d9e28d01e205fba957a5698b1", 16); + mpz_set_str(pub.g, + "07b0f92546150b62514bb771e2a0c0ce387f03bda6c56b50" + "5209ff25fd3c133d89bbcd97e904e09114d9a7defdeadfc9" + "078ea544d2e401aeecc40bb9fbbf78fd87995a10a1c27cb7" + "789b594ba7efb5c4326a9fe59a070e136db77175464adca4" + "17be5dce2f40d10a46a3a3943f26ab7fd9c0398ff8c76ee0" + "a56826a8a88f1dbd", 16); + mpz_set_str(pub.y, + "5df5e01ded31d0297e274e1691c192fe5868fef9e19a8477" + "6454b100cf16f65392195a38b90523e2542ee61871c0440c" + "b87c322fc4b4d2ec5e1e7ec766e1be8d4ce935437dc11c3c" + "8fd426338933ebfe739cb3465f4d3668c5e473508253b1e6" + "82f65cbdc4fae93c2ea212390e54905a86e2223170b44eaa" + "7da5dd9ffcfb7f3b", 16); + test_dsa_sign_deterministic (params, + "411602cb19a6ccc34494d79d98ef1e7ed5af25f7", + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + "81f2f5850be5bc123c43f71a3033e9384611c545", + "4cdd914b65eb6c66a8aaad27299bee6b035f5e89"); + + mpz_set_str(pub.p, + "9db6fb5951b66bb6fe1e140f1d2ce5502374161fd6538df1" + "648218642f0b5c48c8f7a41aadfa187324b87674fa1822b0" + "0f1ecf8136943d7c55757264e5a1a44ffe012e9936e00c1d" + "3e9310b01c7d179805d3058b2a9f4bb6f9716bfe6117c6b5" + "b3cc4d9be341104ad4a80ad6c94e005f4b993e14f091eb51" + "743bf33050c38de235567e1b34c3d6a5c0ceaa1a0f368213" + "c3d19843d0b4b09dcb9fc72d39c8de41f1bf14d4bb4563ca" + "28371621cad3324b6a2d392145bebfac748805236f5ca2fe" + "92b871cd8f9c36d3292b5509ca8caa77a2adfc7bfd77dda6" + "f71125a7456fea153e433256a2261c6a06ed3693797e7995" + "fad5aabbcfbe3eda2741e375404ae25b", 16); + mpz_set_str(pub.q, + "f2c3119374ce76c9356990b465374a17f23f9ed35089bd96" + "9f61c6dde9998c1f", 16); + mpz_set_str(pub.g, + "5c7ff6b06f8f143fe8288433493e4769c4d988ace5be25a0" + "e24809670716c613d7b0cee6932f8faa7c44d2cb24523da5" + "3fbe4f6ec3595892d1aa58c4328a06c46a15662e7eaa703a" + "1decf8bbb2d05dbe2eb956c142a338661d10461c0d135472" + "085057f3494309ffa73c611f78b32adbb5740c361c9f35be" + "90997db2014e2ef5aa61782f52abeb8bd6432c4dd097bc54" + "23b285dafb60dc364e8161f4a2a35aca3a10b1c4d203cc76" + "a470a33afdcbdd92959859abd8b56e1725252d78eac66e71" + "ba9ae3f1dd2487199874393cd4d832186800654760e1e34c" + "09e4d155179f9ec0dc4473f996bdce6eed1cabed8b6f116f" + "7ad9cf505df0f998e34ab27514b0ffe7", 16); + mpz_set_str(pub.y, + "667098c654426c78d7f8201eac6c203ef030d43605032c2f" + "1fa937e5237dbd949f34a0a2564fe126dc8b715c5141802c" + "e0979c8246463c40e6b6bdaa2513fa611728716c2e4fd53b" + "c95b89e69949d96512e873b9c8f8dfd499cc312882561ade" + "cb31f658e934c0c197f2c4d96b05cbad67381e7b768891e4" + "da3843d24d94cdfb5126e9b8bf21e8358ee0e0a30ef13fd6" + "a664c0dce3731f7fb49a4845a4fd8254687972a2d382599c" + "9bac4e0ed7998193078913032558134976410b89d2c171d1" + "23ac35fd977219597aa7d15c1a9a428e59194f75c721ebcb" + "cfae44696a499afa74e04299f132026601638cb87ab79190" + "d4a0986315da8eec6561c938996beadf", 16); + test_dsa_sign_deterministic (params, + "69c7548c21d0dfea6b9a51c9ead4e27c33d3b3f1" + "80316e5bcab92c933f0e4dbc", + &hmac_sha256, + (nettle_hash_update_func *)hmac_sha256_set_key, + (nettle_hash_update_func *)hmac_sha256_update, + (nettle_hash_digest_func *)hmac_sha256_digest, + tstring_data (SHA256_DIGEST_SIZE, digest), /* h */ + "eace8bdbbe353c432a795d9ec556c6d021f7a03f" + "42c36e9bc87e4ac7932cc809", + "7081e175455f9247b812b74583e9e94f9ea79bd6" + "40dc962533b0680793a38d53"); + dsa_public_key_clear(&pub); dsa_private_key_clear(&key); dsa_signature_clear(&signature);
nettle-bugs@lists.lysator.liu.se