[svn] gcry - r1361 - in trunk: cipher doc src

svn author wk cvs at cvs.gnupg.org
Wed Nov 26 12:59:14 CET 2008


Author: wk
Date: 2008-11-26 12:59:14 +0100 (Wed, 26 Nov 2008)
New Revision: 1361

Modified:
   trunk/cipher/ChangeLog
   trunk/cipher/dsa.c
   trunk/cipher/primegen.c
   trunk/doc/gcrypt.texi
   trunk/src/g10lib.h
Log:
Prepare for FIPS186-3.


Modified: trunk/cipher/ChangeLog
===================================================================
--- trunk/cipher/ChangeLog	2008-11-25 21:09:55 UTC (rev 1360)
+++ trunk/cipher/ChangeLog	2008-11-26 11:59:14 UTC (rev 1361)
@@ -1,3 +1,9 @@
+2008-11-26  Werner Koch  <wk at g10code.com>
+
+	* primegen.c (_gcry_generate_fips186_3_prime): New.
+	* dsa.c (generate_fips186): Add arg USE_FIPS186_2.
+	(dsa_generate_ext): Parse new flag use-fips183-2.
+
 2008-11-25  Werner Koch  <wk at g10code.com>
 
 	* dsa.c (generate_fips186): New.

Modified: trunk/cipher/dsa.c
===================================================================
--- trunk/cipher/dsa.c	2008-11-25 21:09:55 UTC (rev 1360)
+++ trunk/cipher/dsa.c	2008-11-26 11:59:14 UTC (rev 1361)
@@ -355,11 +355,12 @@
 
 
 /* Generate a DSA key pair with a key of size NBITS using the
-   algorithm given in FIPS-186.  At the time of implementation FIPS
-   186-3 was not released; the Draft from November 2008 was used
-   instead to avoid limiting ourself to FIPS 186-2.  */
+   algorithm given in FIPS-186-3.  If USE_FIPS186_2 is true,
+   FIPS-186-2 is used and thus the length is restricted to
+   1024/160.  */
 static gpg_err_code_t
 generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
+                  int use_fips186_2,
                   int *r_counter, void **r_seed, size_t *r_seedlen,
                   gcry_mpi_t *r_h)
 {
@@ -397,18 +398,23 @@
     ;
   else if (nbits == 2048 && qbits == 256)
     ;
-  else if (nbits == 2048 && qbits == 256)
+  else if (nbits == 3072 && qbits == 256)
     ;
   else
     return GPG_ERR_INV_VALUE;
 
-  /* Note that we currently do not yet support 186-3 for prime
-     generation becuase it is not clear whether CAVS is prepared for
-     it.  */
-  ec = _gcry_generate_fips186_2_prime (nbits, qbits, NULL, 0,
-                                       &prime_q, &prime_p, 
-                                       r_counter,
-                                       r_seed, r_seedlen);
+  /* Fixme: Enable 186-3 after it has been approved and after fixing
+     the generation fucntion.  */
+/*   if (use_fips186_2) */
+    ec = _gcry_generate_fips186_2_prime (nbits, qbits, NULL, 0,
+                                         &prime_q, &prime_p, 
+                                         r_counter,
+                                         r_seed, r_seedlen);
+/*   else */
+/*     ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */
+/*                                          &prime_q, &prime_p, */
+/*                                          r_counter, */
+/*                                          r_seed, r_seedlen, NULL); */
   if (ec)
     goto leave;
 
@@ -610,6 +616,7 @@
   unsigned int qbits = 0;
   gcry_sexp_t deriveparms = NULL;
   gcry_sexp_t seedinfo = NULL;
+  int use_fips186_2 = 0;
   int use_fips186 = 0;
   
 
@@ -640,23 +647,29 @@
 
       deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0);
 
-      /* Parse the optional "use-fips186" flag.  */
+      /* Parse the optional "use-fips186" flags.  */
       l1 = gcry_sexp_find_token (genparms, "use-fips186", 0);
       if (l1)
         {
           use_fips186 = 1;
           gcry_sexp_release (l1);
         }
+      l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0);
+      if (l1)
+        {
+          use_fips186_2 = 1;
+          gcry_sexp_release (l1);
+        }
     }
 
-  if (deriveparms || use_fips186 || fips_mode ())
+  if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ())
     {
       int counter;
       void *seed;
       size_t seedlen;
       gcry_mpi_t h_value;
 
-      ec = generate_fips186 (&sk, nbits, qbits, 
+      ec = generate_fips186 (&sk, nbits, qbits, use_fips186_2,
                              &counter, &seed, &seedlen, &h_value);
       gcry_sexp_release (deriveparms);
       if (!ec)

Modified: trunk/cipher/primegen.c
===================================================================
--- trunk/cipher/primegen.c	2008-11-25 21:09:55 UTC (rev 1360)
+++ trunk/cipher/primegen.c	2008-11-26 11:59:14 UTC (rev 1361)
@@ -1417,7 +1417,7 @@
 
 /* Generate the two prime used for DSA using the algorithm specified
    in FIPS 186-2.  PBITS is the desired length of the prime P and a
-   QBIST the length of the prime Q.  If SEED is not supplied and
+   QBITS the length of the prime Q.  If SEED is not supplied and
    SEEDLEN is 0 the function generates an appropriate SEED.  On
    success the generated primes are stored at R_Q and R_P, the counter
    value is stored at R_COUNTER and the seed actually used for
@@ -1580,7 +1580,7 @@
     }
 
   /* Step 15:  Save p, q, counter and seed.  */
-/*   log_debug ("fips186-2 nbits p=%u q=%u counter=%d\n", */
+/*   log_debug ("fips186-2 pbits p=%u q=%u counter=%d\n", */
 /*              mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */
 /*   log_printhex("fips186-2 seed:", seed, seedlen);  */
 /*   log_mpidump ("fips186-2 prime p", prime_p); */
@@ -1616,3 +1616,247 @@
   gcry_mpi_release (val_2);
   return ec;
 }
+
+
+
+/* WARNING: The code below has not yet been tested!  However, it is
+   not yet used.  We need to wait for FIPS 186-3 final and for test
+   vectors.
+
+   Generate the two prime used for DSA using the algorithm specified
+   in FIPS 186-3, A.1.1.2.  PBITS is the desired length of the prime P
+   and a QBITS the length of the prime Q.  If SEED is not supplied and
+   SEEDLEN is 0 the function generates an appropriate SEED.  On
+   success the generated primes are stored at R_Q and R_P, the counter
+   value is stored at R_COUNTER and the seed actually used for
+   generation is stored at R_SEED and R_SEEDVALUE.  The hash algorithm
+   used is stored at R_HASHALGO.
+   
+   Note that this function is very similar to the fips186_2 code.  Due
+   to the minor differences, other buffer sizes and for documentarion,
+   we use a separate function.
+*/
+gpg_err_code_t
+_gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits,
+                                const void *seed, size_t seedlen,
+                                gcry_mpi_t *r_q, gcry_mpi_t *r_p,
+                                int *r_counter,
+                                void **r_seed, size_t *r_seedlen,
+                                int *r_hashalgo)
+{
+  gpg_err_code_t ec;
+  unsigned char seed_help_buffer[256/8];  /* Used to hold a generated SEED. */
+  unsigned char *seed_plus;     /* Malloced buffer to hold SEED+x.  */
+  unsigned char digest[256/8];  /* Helper buffer for SHA-1 digest.  */
+  gcry_mpi_t val_2 = NULL;      /* Helper for the prime test.  */
+  gcry_mpi_t tmpval = NULL;     /* Helper variable.  */
+  int hashalgo;                 /* The id of the Approved Hash Function.  */
+  int i;
+  
+  unsigned char value_u[256/8];
+  int value_n, value_b, value_j;
+  int counter;
+  gcry_mpi_t value_w = NULL;
+  gcry_mpi_t value_x = NULL;
+  gcry_mpi_t prime_q = NULL;
+  gcry_mpi_t prime_p = NULL;
+
+  gcry_assert (sizeof seed_help_buffer == sizeof digest
+               && sizeof seed_help_buffer == sizeof value_u);
+
+  /* Step 1:  Check the requested prime lengths.  */
+  /* Note that due to the size of our buffers QBITS is limited to 256.  */
+  if (pbits == 1024 && qbits == 160)
+    hashalgo = GCRY_MD_SHA1;
+  else if (pbits == 2048 && qbits == 224)
+    hashalgo = GCRY_MD_SHA224;
+  else if (pbits == 2048 && qbits == 256)
+    hashalgo = GCRY_MD_SHA256;
+  else if (pbits == 3072 && qbits == 256)
+    hashalgo = GCRY_MD_SHA256;
+  else
+    return GPG_ERR_INV_KEYLEN;
+
+  /* Also check that the hash algorithm is available.  */
+  ec = gpg_err_code (gcry_md_test_algo (hashalgo));
+  if (ec)
+    return ec;
+  gcry_assert (qbits/8 <= sizeof digest);
+  gcry_assert (gcry_md_get_algo_dlen (hashalgo) == qbits/8);
+
+
+  /* Step 2:  Check seedlen.  */
+  if (!seed && !seedlen)
+    ; /* No seed value given:  We are asked to generate it.  */
+  else if (!seed || seedlen < qbits/8)
+    return GPG_ERR_INV_ARG;
+  
+  /* Allocate a buffer to later compute SEED+some_increment and a few
+     helper variables.  */
+  seed_plus = gcry_malloc (seedlen < sizeof seed_help_buffer? 
+                           sizeof seed_help_buffer : seedlen);
+  if (!seed_plus)
+    {
+      ec = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+  val_2   = mpi_alloc_set_ui (2);
+  value_w = gcry_mpi_new (pbits);
+  value_x = gcry_mpi_new (pbits);
+
+  /* Step 3: n = \lceil L / outlen \rceil - 1  */
+  value_n = (pbits + qbits - 1) / qbits - 1;
+  /* Step 4: b = L - 1 - (n * outlen)  */
+  value_b = pbits - 1 - (value_n * qbits);
+
+ restart:  
+  /* Generate Q.  */
+  for (;;)
+    {
+      /* Step 5:  Generate a (new) seed unless one has been supplied.  */
+      if (!seed)
+        {
+          seedlen = qbits/8;
+          gcry_assert (seedlen <= sizeof seed_help_buffer);
+          gcry_create_nonce (seed_help_buffer, seedlen);
+          seed = seed_help_buffer;
+        }
+      
+      /* Step 6:  U = hash(seed)  */
+      gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen);
+
+      /* Step 7:  q = 2^{N-1} + U + 1 - (U mod 2)  */
+      if ( !(value_u[qbits/8-1] & 0x01) )
+        {
+          for (i=qbits/8-1; i >= 0; i--)
+            {
+              value_u[i]++;
+              if (value_u[i])
+                break;
+            }
+        }
+      gcry_mpi_release (prime_q); prime_q = NULL;
+      ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, 
+                                        value_u, sizeof value_u, NULL));
+      if (ec)
+        goto leave;
+      mpi_set_highbit (prime_q, qbits-1 );
+      
+      /* Step 8:  Test whether Q is prime using 64 round of Rabin-Miller.
+                  According to table C.1 this is sufficient for all
+                  supported prime sizes (i.e. up 3072/256).  */
+      if (check_prime (prime_q, val_2, 64, NULL, NULL))
+        break; /* Yes, Q is prime.  */
+
+      /* Step 8.  */
+      seed = NULL;  /* Force a new seed at Step 5.  */
+    }
+  
+  /* Step 11.  Note that we do no use an explicit offset but increment
+     SEED_PLUS accordingly.  */
+  memcpy (seed_plus, seed, seedlen);
+  counter = 0;
+
+  /* Generate P. */
+  prime_p = gcry_mpi_new (pbits);
+  for (;;)
+    {
+      /* Step 11.1: For j = 0,...n let 
+                      V_j = hash(seed+offset+j)  
+         Step 11.2: W = V_0 + V_1*2^outlen + 
+                            ... 
+                            + V_{n-1}*2^{(n-1)*outlen}
+                            + (V_{n} mod 2^b)*2^{n*outlen}                
+       */
+      mpi_set_ui (value_w, 0);
+      for (value_j=0; value_j <= value_n; value_j++)
+        {
+          /* There is no need to have an explicit offset variable: In
+             the first round we shall have an offset of 1 and a j of
+             0.  This is achieved by incrementing SEED_PLUS here.  For
+             the next round offset is implicitly updated by using
+             SEED_PLUS again.  */
+          for (i=seedlen-1; i >= 0; i--)
+            {
+              seed_plus[i]++;
+              if (seed_plus[i])
+                break;
+            }
+          gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen);
+          
+          gcry_mpi_release (tmpval); tmpval = NULL;
+          ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG,
+                                            digest, sizeof digest, NULL));
+          if (ec)
+            goto leave;
+          if (value_j == value_n)
+            mpi_clear_highbit (tmpval, value_b+1); /* (V_n mod 2^b) */
+          mpi_lshift (tmpval, tmpval, value_j*qbits);
+          mpi_add (value_w, value_w, tmpval);
+        }
+
+      /* Step 11.3: X = W + 2^{L-1}  */
+      mpi_set_ui (value_x, 0);
+      mpi_set_highbit (value_x, pbits-1);
+      mpi_add (value_x, value_x, value_w);
+
+      /* Step 11.4:  c = X mod 2q  */
+      mpi_mul_2exp (tmpval, prime_q, 1);
+      mpi_mod (tmpval, value_x, tmpval);
+
+      /* Step 11.5:  p = X - (c - 1)  */
+      mpi_sub_ui (tmpval, tmpval, 1);
+      mpi_sub (prime_p, value_x, tmpval);
+
+      /* Step 11.6: If  p < 2^{L-1}  skip the primality test.  */
+      /* Step 11.7 and 11.8: Primality test.  */
+      if (mpi_get_nbits (prime_p) >= pbits-1
+          && check_prime (prime_p, val_2, 64, NULL, NULL) )
+        break; /* Yes, P is prime, continue with Step 15.  */
+      
+      /* Step 11.9: counter = counter + 1, offset = offset + n + 1.
+                    If counter >= 4L  goto Step 5.  */
+      counter++;
+      if (counter >= 4*pbits)
+        goto restart;
+    }
+
+  /* Step 12:  Save p, q, counter and seed.  */
+  log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n",
+             mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter);
+  log_printhex("fips186-3 seed:", seed, seedlen);
+  log_mpidump ("fips186-3 prime p", prime_p);
+  log_mpidump ("fips186-3 prime q", prime_q);
+  if (r_q)
+    {
+      *r_q = prime_q;
+      prime_q = NULL;
+    }
+  if (r_p)
+    {
+      *r_p = prime_p;
+      prime_p = NULL;
+    }
+  if (r_counter)
+    *r_counter = counter;
+  if (r_seed && r_seedlen)
+    {
+      memcpy (seed_plus, seed, seedlen);
+      *r_seed = seed_plus;
+      seed_plus = NULL;
+      *r_seedlen = seedlen;
+    }
+  if (r_hashalgo)
+    *r_hashalgo = hashalgo;
+
+ leave:
+  gcry_mpi_release (tmpval);
+  gcry_mpi_release (value_x);
+  gcry_mpi_release (value_w);
+  gcry_mpi_release (prime_p);
+  gcry_mpi_release (prime_q);
+  gcry_free (seed_plus);
+  gcry_mpi_release (val_2);
+  return ec;
+}
+

Modified: trunk/doc/gcrypt.texi
===================================================================
--- trunk/doc/gcrypt.texi	2008-11-25 21:09:55 UTC (rev 1360)
+++ trunk/doc/gcrypt.texi	2008-11-26 11:59:14 UTC (rev 1361)
@@ -2759,12 +2759,19 @@
 either @code{derive-parms} is given or Libgcrypt is in FIPS mode.
 
 @item use-fips186
+Force the use of the FIPS 186 key generation algorithm instead of the
+default algorithm.  This flag is only meaningful for DSA and usually
+not required.  Note that this algorithm is implicitly used if either
+ at code{derive-parms} is given or Libgcrypt is in FIPS mode.  As of now
+FIPS 186-2 is implemented; after the approval of FIPS 186-3 the code
+will be changed to implement 186-3.
+
+
+ at item use-fips186-2
 Force the use of the FIPS 186-2 key generation algorithm instead of
-the default algorithm.  This flag is only meaningful for DSA and
-usually not required.  Note that this algorithm is implicitly used if
-either @code{derive-parms} is given or Libgcrypt is in FIPS mode.
-This implementation may be changed in future to use the forthcoming
-FIPS 186-3 algorithm.
+the default algorithm.  This algorithm has a slighlty different from
+FIPS 186-3 and allws only 1024 bit keys.  This flag is only meaningful
+for DSA and only required for FIPS testing backward compatibility.
 
 
 @end table

Modified: trunk/src/g10lib.h
===================================================================
--- trunk/src/g10lib.h	2008-11-25 21:09:55 UTC (rev 1360)
+++ trunk/src/g10lib.h	2008-11-26 11:59:14 UTC (rev 1361)
@@ -185,9 +185,15 @@
                   gcry_mpi_t *r_q, gcry_mpi_t *r_p,
                   int *r_counter,
                   void **r_seed, size_t *r_seedlen);
+gpg_err_code_t _gcry_generate_fips186_3_prime 
+                 (unsigned int pbits, unsigned int qbits,
+                  const void *seed, size_t seedlen,
+                  gcry_mpi_t *r_q, gcry_mpi_t *r_p,
+                  int *r_counter,
+                  void **r_seed, size_t *r_seedlen, int *r_hashalgo);
 
 
-/* replacements of missing functions (missing-string.c)*/
+/* Replacements of missing functions (missing-string.c).  */
 #ifndef HAVE_STPCPY
 char *stpcpy (char *a, const char *b);
 #endif
@@ -195,7 +201,7 @@
 int strcasecmp (const char *a, const char *b) _GCRY_GCC_ATTR_PURE;
 #endif
 
-/* macros used to rename missing functions */
+/* Macros used to rename missing functions.  */
 #ifndef HAVE_STRTOUL
 #define strtoul(a,b,c)  ((unsigned long)strtol((a),(b),(c)))
 #endif




More information about the Gnupg-commits mailing list