]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
gmp: Use NIST DRBG for RSA key pair generation
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 16 Oct 2019 09:57:22 +0000 (11:57 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 18 Oct 2019 14:24:39 +0000 (16:24 +0200)
src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c

index 2d2d5c6fb64af4cbc63866b537f6b56f17152856..852e2359a56539bbed145270868a3e80219c1c4c 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 2017-2018 Tobias Brunner
  * Copyright (C) 2005 Jan Hutter
  * Copyright (C) 2005-2009 Martin Willi
- * Copyright (C) 2012 Andreas Steffen
+ * Copyright (C) 2012-2019 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -155,31 +155,23 @@ static void mpz_clear_sensitive(mpz_t z)
 /**
  * Create a mpz prime of at least prime_size
  */
-static status_t compute_prime(size_t prime_size, bool safe, mpz_t *p, mpz_t *q)
+static status_t compute_prime(drbg_t *drbg, size_t prime_size, bool safe, mpz_t *p, mpz_t *q)
 {
-       rng_t *rng;
        chunk_t random_bytes;
        int count = 0;
 
-       rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
-       if (!rng)
-       {
-               DBG1(DBG_LIB, "no RNG of quality %N found", rng_quality_names,
-                        RNG_TRUE);
-               return FAILED;
-       }
-
        mpz_init(*p);
        mpz_init(*q);
+       random_bytes = chunk_alloc(prime_size);
 
        do
        {
-               if (!rng->allocate_bytes(rng, prime_size, &random_bytes))
+               if (!drbg->generate(drbg, random_bytes.len, random_bytes.ptr))
                {
                        DBG1(DBG_LIB, "failed to allocate random prime");
                        mpz_clear(*p);
                        mpz_clear(*q);
-                       rng->destroy(rng);
+                       chunk_free(&random_bytes);
                        return FAILED;
                }
 
@@ -205,13 +197,11 @@ static status_t compute_prime(size_t prime_size, bool safe, mpz_t *p, mpz_t *q)
                        mpz_import(*p, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
                        mpz_nextprime (*p, *p);
                }
-               chunk_clear(&random_bytes);
        }
-
        /* check if the prime isn't too large */
        while (((mpz_sizeinbase(*p, 2) + 7) / 8) > prime_size);
 
-       rng->destroy(rng);
+       chunk_clear(&random_bytes);
 
        /* additionally return p-1 */
        mpz_sub_ui(*q, *p, 1);
@@ -789,10 +779,14 @@ static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void)
 gmp_rsa_private_key_t *gmp_rsa_private_key_gen(key_type_t type, va_list args)
 {
        private_gmp_rsa_private_key_t *this;
-       u_int key_size = 0, shares = 0, threshold = 1;
-       bool safe_prime = FALSE, rng_failed = FALSE, invert_failed = FALSE;
-       mpz_t p, q, p1, q1, d;
-;
+       drbg_type_t drbg_type = DRBG_HMAC_SHA512;
+       drbg_t* drbg;
+       rng_t *rng;
+       u_int strength = 256, key_size = 0, shares = 0, threshold = 1;
+       bool safe_prime = FALSE, drbg_failed = FALSE, invert_failed = FALSE;
+       mpz_t p, q, p1, q1;
+       int i;
+
 
        while (TRUE)
        {
@@ -823,15 +817,35 @@ gmp_rsa_private_key_t *gmp_rsa_private_key_gen(key_type_t type, va_list args)
        }
        key_size = key_size / BITS_PER_BYTE;
 
+       /* Initiate a NIST SP 800-90A DRBG fed by a true random generator */
+       rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
+       if (!rng)
+       {
+               DBG1(DBG_LIB, "no RNG of quality %N found", rng_quality_names, RNG_TRUE);
+               return NULL;
+       }
+       drbg = lib->crypto->create_drbg(lib->crypto, drbg_type, strength, rng,
+                                                                       chunk_empty);
+       if (!drbg)
+       {
+               DBG1(DBG_LIB, "instantiation of %N failed", drbg_type_names, drbg_type);
+               rng->destroy(rng);
+               return NULL;
+       }
+
        /* Get values of primes p and q  */
-       if (compute_prime(key_size/2, safe_prime, &p, &p1) != SUCCESS)
+       if (compute_prime(drbg, key_size/2, safe_prime, &p, &p1) != SUCCESS)
        {
+               drbg->destroy(drbg);
+               rng->destroy(rng);
                return NULL;
        }
-       if (compute_prime(key_size/2, safe_prime, &q, &q1) != SUCCESS)
+       if (compute_prime(drbg, key_size/2, safe_prime, &q, &q1) != SUCCESS)
        {
                mpz_clear(p);
                mpz_clear(p1);
+               drbg->destroy(drbg);
+               rng->destroy(rng);
                return NULL;
        }
 
@@ -844,11 +858,17 @@ gmp_rsa_private_key_t *gmp_rsa_private_key_gen(key_type_t type, va_list args)
 
        /* Create and initialize RSA private key object */
        this = gmp_rsa_private_key_create_empty();
+       *this->p = *p;
+       *this->q = *q;
+
+       /* allocate space for private exponent d with optional threshold scheme */
        this->shares = shares;
        this->threshold = threshold;
        this->d = malloc(threshold * sizeof(mpz_t));
-       *this->p = *p;
-       *this->q = *q;
+       for (i = 0; i < threshold; i++)
+       {
+               mpz_init(this->d[i]);
+       }
 
        mpz_init_set_ui(this->e, PUBLIC_EXPONENT);
        mpz_init(this->n);
@@ -857,71 +877,62 @@ gmp_rsa_private_key_t *gmp_rsa_private_key_gen(key_type_t type, va_list args)
        mpz_init(this->exp2);
        mpz_init(this->coeff);
        mpz_init(this->v);
-       mpz_init(d);
 
-       mpz_mul(this->n, p, q);                                 /* n = p*q */
-       mpz_lcm(this->m, p1, q1);                               /* m = lcm(p-1,q-1) */
-       mpz_invert(d, this->e, this->m);                /* e has an inverse mod m */
-       mpz_mod(this->exp1, d, p1);                             /* exp1 = d mod p-1 */
-       mpz_mod(this->exp2, d, q1);                             /* exp2 = d mod q-1 */
-       mpz_invert(this->coeff, q, p);                  /* coeff = q^-1 mod p */
+       mpz_mul(this->n, p, q);                    /* n = p*q */
+       mpz_lcm(this->m, p1, q1);                  /* m = lcm(p-1,q-1) */
+       mpz_invert(this->d[0], this->e, this->m);  /* e has an inverse mod m */
+       mpz_mod(this->exp1, this->d[0], p1);       /* exp1 = d mod p-1 */
+       mpz_mod(this->exp2, this->d[0], q1);       /* exp2 = d mod q-1 */
+       mpz_invert(this->coeff, q, p);             /* coeff = q^-1 mod p */
 
        invert_failed = mpz_cmp_ui(this->m, 0) == 0 ||
                                        mpz_cmp_ui(this->coeff, 0) == 0;
 
-    /* store secret exponent d */
-       (*this->d)[0] = *d;
-
        /* generate and store random coefficients of secret sharing polynomial */
        if (threshold > 1)
        {
-               rng_t *rng;
                chunk_t random_bytes;
                mpz_t u;
-               int i;
 
-               rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
                mpz_init(u);
+               random_bytes = chunk_alloc(key_size);
 
                for (i = 1; i < threshold; i++)
                {
-                       mpz_init(d);
-
-                       if (!rng->allocate_bytes(rng, key_size, &random_bytes))
+                       if (!drbg->generate(drbg, random_bytes.len, random_bytes.ptr))
                        {
-                               rng_failed = TRUE;
+                               drbg_failed = TRUE;
                                continue;
                        }
-                       mpz_import(d, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
-                       mpz_mod(d, d, this->m);
-                       (*this->d)[i] = *d;
-                       chunk_clear(&random_bytes);
+                       mpz_import(this->d[i], random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
+                       mpz_mod(this->d[i], this->d[i], this->m);
                }
 
                /* generate verification key v as a square number */
                do
                {
-                       if (!rng->allocate_bytes(rng, key_size, &random_bytes))
+                       if (!drbg->generate(drbg, random_bytes.len, random_bytes.ptr))
                        {
-                               rng_failed = TRUE;
+                               drbg_failed = TRUE;
                                break;
                        }
                        mpz_import(this->v, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
                        mpz_mul(this->v, this->v, this->v);
                        mpz_mod(this->v, this->v, this->n);
                        mpz_gcd(u, this->v, this->n);
-                       chunk_free(&random_bytes);
                }
                while (mpz_cmp_ui(u, 1) != 0);
 
                mpz_clear(u);
-               rng->destroy(rng);
+               chunk_clear(&random_bytes);
        }
 
        mpz_clear_sensitive(p1);
        mpz_clear_sensitive(q1);
+       drbg->destroy(drbg);
+       rng->destroy(rng);
 
-       if (rng_failed || invert_failed)
+       if (drbg_failed || invert_failed)
        {
                DBG1(DBG_LIB, "rsa key generation failed");
                destroy(this);