diff --git a/dsa-keygen.c b/dsa-keygen.c new file mode 100644 index 0000000000000000000000000000000000000000..a09375e17bcc005e367ecb9b76bd404f0bfda57e --- /dev/null +++ b/dsa-keygen.c @@ -0,0 +1,236 @@ +/* dsa-keygen.c + * + * Generation of DSA keypairs + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2002 Niels M�ller + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#if WITH_PUBLIC_KEY + +#include "dsa.h" + +#include "bignum.h" +#include "memxor.h" + +#include <stdlib.h> + +/* The (slow) NIST method of generating DSA primes. Algorithm 4.56 of + * Handbook of Applied Cryptography. */ + +#define SEED_LENGTH SHA1_DIGEST_SIZE +#define SEED_BITS (SEED_LENGTH * 8) + +static void +hash(mpz_t x, uint8_t *digest) +{ + mpz_t t; + uint8_t data[SEED_LENGTH]; + struct sha1_ctx ctx; + + mpz_init_set(t, x); + mpz_fdiv_r_2exp(t, t, SEED_BITS); + + nettle_mpz_get_str_256(SEED_LENGTH, data, t); + mpz_clear(t); + + sha1_init(&ctx); + sha1_update(&ctx, SEED_LENGTH, data); + sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest); +} + +static void +dsa_nist_gen(mpz_t p, mpz_t q, + void *random_ctx, nettle_random_func random, + void *progress_ctx, nettle_progress_func progress, + unsigned L) +{ + unsigned n; + unsigned b; + mpz_t s; + mpz_t t; + mpz_t c; + + /* For NIS keysizes, we should have L = 512 + 65 * l */ + n = (L-1) / 160; b = (L-1) % 160; + + mpz_init(s); + mpz_init(t); + mpz_init(c); + + for (;;) + { + { /* Generate q */ + uint8_t h1[SHA1_DIGEST_SIZE]; + uint8_t h2[SHA1_DIGEST_SIZE]; + + progress(progress_ctx, '.'); + + nettle_mpz_random_size(s, random_ctx, random, SEED_BITS); + + hash(s, h1); + + mpz_set(t, s); + mpz_add_ui(t, t, 1); + + hash(t, h2); + + memxor(h1, h2, SHA1_DIGEST_SIZE); + + h1[0] |= 0x80; + h1[SHA1_DIGEST_SIZE - 1] |= 1; + + nettle_mpz_set_str_256(q, SHA1_DIGEST_SIZE, h1); + + /* The spec says that we should use 18 iterations of + * miller-rabin. For performance, we want to do some trial + * divisions first. The curent version of mpz_probab_prime_p + * does exactly that. */ + if (!mpz_probab_prime_p(q, 18)) + /* Try new seed. */ + continue; + } + /* q is a prime, with overwhelming probability. */ + + { + unsigned size = (n+1) * SHA1_DIGEST_SIZE; + uint8_t *buffer = alloca(size); + unsigned i, j; + + for (i = 0, j = 2; i<4096; i++, j+= n+1) + { + unsigned k; + + progress(progress_ctx, ','); + for (k = 0; k<=n ; k++) + { + mpz_set(t, s); + mpz_add_ui(t, t, j + k); + hash(t, buffer + ( (n-k) * SHA1_DIGEST_SIZE)); + } + nettle_mpz_set_str_256(p, size, buffer); + + mpz_fdiv_r_2exp(p, p, L); + mpz_setbit(p, L-1); + + mpz_set(t, q); + mpz_mul_2exp(t, t, 1); + + mpz_fdiv_r(c, p, t); + + mpz_sub_ui(c, c, 1); + + mpz_sub(p, p, c); + + if (mpz_probab_prime_p(p, 5)) + { + /* Done! */ + mpz_clear(s); + mpz_clear(t); + mpz_clear(c); + + return; + } + } + progress(progress_ctx, '+'); + } + } +} + +static void +dsa_find_generator(mpz_t g, + void *random_ctx, nettle_random_func random, + void *progress_ctx, nettle_progress_func progress, + const mpz_t p, const mpz_t q) +{ + mpz_t e; + mpz_t n; + + /* e = (p-1)/q */ + mpz_init_set(e, p); + mpz_sub_ui(e, e, 1); + mpz_divexact(e, e, q); + + /* n = p-2 = |2, 3, ... p-1| */ + mpz_init_set(n, p); + mpz_sub_ui(n, n, 2); + + for (;;) + { + nettle_mpz_random(g, random_ctx, random, n); + mpz_add_ui(g, g, 2); + + progress(progress_ctx, 'g'); + mpz_powm(g, g, e, p); + + if (mpz_cmp_ui(g, 1)) + { + /* g != 1. Finished. */ + mpz_clear(e); + mpz_clear(n); + + return; + } + } +} + +int +dsa_generate_keypair(struct dsa_public_key *pub, + struct dsa_private_key *key, + void *random_ctx, nettle_random_func random, + void *progress_ctx, nettle_progress_func progress, + /* Size of key, in bits. + * Use size = 512 + 64 * l for the official + * NIS key sizes. */ + unsigned bits) +{ + mpz_t t; + + if (bits < DSA_MINIMUM_BITS) + return 0; + + dsa_nist_gen(pub->p, pub->q, + random_ctx, random, + progress_ctx, progress, + bits); + + dsa_find_generator(pub->g, + random_ctx, random, + progress_ctx, progress, + pub->p, pub->q); + + mpz_init_set(t, pub->q); + mpz_sub_ui(t, t, 2); + nettle_mpz_random(key->x, random_ctx, random, t); + + mpz_add_ui(key->x, key->x, 1); + + mpz_powm(pub->y, pub->g, key->x, pub->p); + + mpz_clear(t); + + return 1; +} + +#endif /* WITH_PUBLIC_KEY */