From e89a1126494e764fee659879e4fc1165c05d661f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Wed, 16 Jan 2002 21:07:25 +0100 Subject: [PATCH] New file. Rev: src/nettle/rsa-keygen.c:1.1 --- rsa-keygen.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 rsa-keygen.c diff --git a/rsa-keygen.c b/rsa-keygen.c new file mode 100644 index 00000000..2d2cc922 --- /dev/null +++ b/rsa-keygen.c @@ -0,0 +1,346 @@ +/* rsa-keygen.c + * + * Generation of RSA 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 HAVE_LIBGMP + +#include "rsa.h" +#include "bignum.h" + +#include <assert.h> +#include <limits.h> +#include <stdlib.h> + +#ifndef DEBUG +# define DEBUG 0 +#endif + +#if DEBUG +# include <stdio.h> +#endif + +/* Returns a random number, 0 <= x < 2^bits. */ +static void +bignum_random_size(mpz_t x, unsigned bits, + void *random_ctx, nettle_random_func random) +{ + unsigned length = (bits + 7) / 8; + uint8_t *data = alloca(length); + + random(random_ctx, length, data); + + nettle_mpz_set_str_256(x, length, data); + + if (bits % 8) + mpz_fdiv_r_2exp(x, x, bits); +} + +#define NUMBER_OF_PRIMES 167 + +static const unsigned long primes[NUMBER_OF_PRIMES] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, + 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, + 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, + 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, + 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, + 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, + 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, + 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, + 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, + 977, 983, 991, 997 +}; + +/* NOTE: The mpz_nextprime in current GMP is unoptimized. */ +static void +bignum_next_prime(mpz_t p, mpz_t n, int count, + void *progress_ctx, nettle_progress_func progress) +{ + mpz_t tmp; + unsigned long *moduli = NULL; + unsigned long difference; + int prime_limit = NUMBER_OF_PRIMES; + + /* First handle tiny numbers */ + if (mpz_cmp_ui(n, 2) <= 0) + { + mpz_set_ui(p, 2); + return; + } + mpz_set(p, n); + mpz_setbit(p, 0); + + if (mpz_cmp_ui(p, 8) < 0) + return; + + mpz_init(tmp); + + if (prime_limit && (mpz_cmp_ui(p, primes[prime_limit]) <= 0) ) + /* Use unly 3, 5 and 7 */ + prime_limit = 3; + + if (prime_limit) + { + /* Compute residues modulo small odd primes */ + int i; + + moduli = alloca(prime_limit * sizeof(*moduli)); + for (i = 0; i < prime_limit; i++) + moduli[i] = mpz_fdiv_ui(p, primes[i]); + } + + for (difference = 0; ; difference += 2) + { + if (difference >= ULONG_MAX - 10) + { /* Should not happen, at least not very often... */ + mpz_add_ui(p, p, difference); + difference = 0; + } + + /* First check residues */ + if (prime_limit) + { + int composite = 0; + int i; + + for (i = 0; i < prime_limit; i++) + { + if (moduli[i] == 0) + composite = 1; + moduli[i] = (moduli[i] + 2) % primes[i]; + } + if (composite) + continue; + } + + mpz_add_ui(p, p, difference); + difference = 0; + + if (progress) + progress(progress_ctx, '.'); + + /* Fermat test, with respect to 2 */ + mpz_set_ui(tmp, 2); + mpz_powm(tmp, tmp, p, p); + if (mpz_cmp_ui(tmp, 2) != 0) + continue; + + if (progress) + progress(progress_ctx, '+'); + + /* Miller-Rabin test */ + if (mpz_probab_prime_p(p, count)) + break; + } + mpz_clear(tmp); +} + +/* Returns a random prime of size BITS */ +static void +bignum_random_prime(mpz_t x, unsigned bits, + void *random_ctx, nettle_random_func random, + void *progress_ctx, nettle_progress_func progress) +{ + assert(bits); + + for (;;) + { + bignum_random_size(x, bits, random_ctx, random); + mpz_setbit(x, bits - 1); + + /* Miller-rabin count of 25 is probably much overkill. */ + bignum_next_prime(x, x, 25, progress_ctx, progress); + + if (mpz_sizeinbase(x, 2) == bits) + break; + } +} + +int +rsa_generate_keypair(struct rsa_public_key *pub, + struct rsa_private_key *key, + void *random_ctx, nettle_random_func random, + void *progress_ctx, nettle_progress_func progress, + unsigned n_size, + unsigned e_size) +{ + mpz_t p1; + mpz_t q1; + mpz_t phi; + mpz_t tmp; + + if (e_size) + { + /* We should choose e randomly. Is the size reasonable? */ + if ((e_size < 16) || (e_size > n_size) ) + return 0; + } + else + { + /* We have a fixed e. Check that it makes sense */ + + /* It must be odd */ + if (!mpz_tstbit(pub->e, 0)) + return 0; + + /* And 3 or larger */ + if (mpz_cmp_ui(pub->e, 3) < 0) + return 0; + } + + if (n_size < RSA_MINIMUM_N_BITS) + return 0; + + mpz_init(p1); mpz_init(q1); mpz_init(phi); mpz_init(tmp); + + /* Generate primes */ + for (;;) + { + /* Generate p, such that gcd(p-1, e) = 1 */ + for (;;) + { + bignum_random_prime(key->p, (n_size+1)/2, + random_ctx, random, + progress_ctx, progress); + mpz_sub_ui(p1, key->p, 1); + + /* If e was given, we must chose p such that p-1 has no factors in + * common with e. */ + if (e_size) + break; + + mpz_gcd(tmp, pub->e, p1); + + if (mpz_cmp_ui(tmp, 1) == 0) + break; + else if (progress) progress(progress_ctx, 'c'); + } + + if (progress) + progress(progress_ctx, '\n'); + + /* Generate q, such that gcd(q-1, e) = 1 */ + for (;;) + { + bignum_random_prime(key->q, n_size/2, + random_ctx, random, + progress_ctx, progress); + mpz_sub_ui(q1, key->q, 1); + + /* If e was given, we must chose q such that q-1 has no factors in + * common with e. */ + if (e_size) + break; + + mpz_gcd(tmp, pub->e, q1); + + if (mpz_cmp_ui(tmp, 1) == 0) + break; + else if (progress) progress(progress_ctx, 'c'); + } + + /* Now we have the primes. Is the product of the right size? */ + mpz_mul(pub->n, key->p, key->q); + + if (mpz_sizeinbase(pub->n, 2) != n_size) + /* We might get an n of size n_size-1. Then just try again. */ + { +#if DEBUG + fprintf(stderr, + "\nWanted size: %d, p-size: %d, q-size: %d, n-size: %d\n", + n_size, + mpz_sizeinbase(key->p,2), + mpz_sizeinbase(key->q,2), + mpz_sizeinbase(pub->n,2)); +#endif + if (progress) + { + progress(progress_ctx, 'b'); + progress(progress_ctx, '\n'); + } + continue; + } + + if (progress) + progress(progress_ctx, '\n'); + + /* c = q^{-1} (mod p) */ + if (mpz_invert(key->c, key->q, key->p)) + /* This should succeed everytime. But if it doesn't, + * we try again. */ + break; + else if (progress) progress(progress_ctx, '?'); + } + + mpz_mul(phi, p1, q1); + + /* If we didn't have a given e, generate one now. */ + if (e_size) + for (;;) + { + bignum_random_size(pub->e, e_size, + random_ctx, random); + + /* Make sure it's odd and that the most significant bit is + * set */ + mpz_setbit(pub->e, 0); + mpz_setbit(pub->e, e_size - 1); + + /* Needs gmp-3, or inverse might be negative. */ + if (mpz_invert(key->d, pub->e, phi)) + break; + else if (progress) progress(progress_ctx, 'e'); + } + else + { + /* Must always succeed, as we already that e + * doesn't have any common factor with p-1 or q-1. */ + int res = mpz_invert(key->d, pub->e, phi); + assert(res); + } + + /* Done! Almost, we must compute the auxillary private values. */ + /* a = d % (p-1) */ + mpz_fdiv_r(key->a, key->d, p1); + + /* b = d % (q-1) */ + mpz_fdiv_r(key->b, key->d, q1); + + /* c was computed earlier */ + + pub->size = key->size = (mpz_sizeinbase(pub->n, 2) + 7) / 8; + assert(pub->size >= RSA_MINIMUM_N_OCTETS); + + mpz_clear(p1); mpz_clear(q1); mpz_clear(phi); mpz_clear(tmp); + + return 1; +} + +#endif /* HAVE_LIBGMP */ -- GitLab