implemented an optional DH public value test
authorMartin Willi <martin@strongswan.org>
Thu, 4 Oct 2007 15:19:24 +0000 (15:19 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 4 Oct 2007 15:19:24 +0000 (15:19 -0000)
some other cleanups, using RFC2631 variable names

src/libstrongswan/crypto/diffie_hellman.c
src/libstrongswan/crypto/diffie_hellman.h

index 7b8f455..7b33ae4 100644 (file)
@@ -8,7 +8,7 @@
 /*
  * Copyright (C) 1998-2002  D. Hugh Redelmeier.
  * Copyright (C) 1999, 2000, 2001  Henry Spencer.
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -24,7 +24,6 @@
  */
 
 #include <gmp.h>
-#include <stdio.h>
 
 #include "diffie_hellman.h"
 
@@ -322,7 +321,7 @@ struct modulus_entry_t {
        /* 
         * Length of modulus in bytes.
         */     
-       size_t modulus_length;
+       size_t modulus_len;
        
        /* 
         * Generator value.
@@ -359,42 +358,42 @@ struct private_diffie_hellman_t {
        /**
         * Diffie Hellman group number.
         */
-       u_int16_t dh_group_number;
-
-       /**
-        * Modulus.
-        */
-       mpz_t modulus;
-       
-       /**
-        * Modulus length.
-        */
-       size_t modulus_length;
+       u_int16_t group;
        
        /* 
         * Generator value.
         */     
-       u_int16_t generator;
+       mpz_t g;
 
        /**
-        * My private value .
+        * My private value.
         */
-       mpz_t private;
+       mpz_t xa;
        
        /**
         * My public value.
         */
-       mpz_t my_public;
+       mpz_t ya;
 
        /**
         * Other public value.
         */     
-       mpz_t other_public;
+       mpz_t yb;
        
        /**
         * Shared secret.
         */     
-       mpz_t secret;
+       mpz_t zz;
+
+       /**
+        * Modulus.
+        */
+       mpz_t p;
+       
+       /**
+        * Modulus length.
+        */
+       size_t p_len;
 
        /**
         * True if shared secret is computed and stored in my_public_value.
@@ -403,31 +402,52 @@ struct private_diffie_hellman_t {
 };
 
 /**
- * Compute the shared secret
- */
-static void compute_shared_secret(private_diffie_hellman_t *this)
-{
-       mpz_powm(this->secret, this->other_public, this->private, this->modulus);
-       this->computed = TRUE;
-}
-
-/**
  * Implementation of diffie_hellman_t.set_other_public_value.
  */
 static void set_other_public_value(private_diffie_hellman_t *this, chunk_t value)
 {
-       mpz_import(this->other_public, value.len, 1, 1, 1, 0, value.ptr);
+       mpz_t p_min_1;
+       
+       mpz_init(p_min_1);
+       mpz_sub_ui(p_min_1, this->p, 1);
+       
+       mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr);
        
-       /* check public value: */
-       /* 1. 0 or 1 wouldn't include your generated value */
-       /* 2. a public value larger or equal the modulus is invalid anyway */
-       if (mpz_cmp_ui(this->other_public, 1) <= 0 ||
-               mpz_cmp(this->other_public, this->modulus) >= 0)
+       /* check public value: 
+        * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
+        * 2. a public value larger or equal the modulus is invalid */
+       if (mpz_cmp_ui(this->yb, 1) > 0 ||
+               mpz_cmp(this->yb, p_min_1) < 0)
        {
-               DBG1("public DH value verification failed: 0/1");
-               return;
+#ifdef EXTENDED_DH_TEST
+               /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */
+               mpz_t q, one;
+               
+               mpz_init(q);
+               mpz_init(one);
+               mpz_fdiv_q_2exp(q, p_min_1, 1);
+               mpz_powm(one, this->yb, q, this->p);
+               mpz_clear(q);
+               if (mpz_cmp_ui(one, 1) == 0)
+               {
+                       mpz_powm(this->zz, this->yb, this->xa, this->p);
+                       this->computed = TRUE;
+               }
+               else
+               {
+                       DBG1("public DH value verification failed: y ^ q mod p != 1");
+               }
+               mpz_clear(one);
+#else
+               mpz_powm(this->zz, this->yb, this->xa, this->p);
+               this->computed = TRUE;
+#endif
+       }
+       else
+       {
+               DBG1("public DH value verification failed: y < 2 || y > p - 1 ");
        }
-       compute_shared_secret(this);
+       mpz_clear(p_min_1);
 }
 
 /**
@@ -440,32 +460,18 @@ static status_t get_other_public_value(private_diffie_hellman_t *this,
        {
                return FAILED;
        }
-       value->len = this->modulus_length;
-    value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->other_public);
+       value->len = this->p_len;
+    value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->yb);
        return SUCCESS;
 }
 
-
-/**
- * Implementation of private_diffie_hellman_t.compute_public_value.
- */
-static void compute_public_value(private_diffie_hellman_t *this)
-{
-       mpz_t generator;
-       
-       mpz_init_set_ui(generator, this->generator);
-       mpz_powm(this->my_public, generator, this->private, this->modulus);
-       
-       mpz_clear(generator);
-}
-
 /**
  * Implementation of diffie_hellman_t.get_my_public_value.
  */
 static void get_my_public_value(private_diffie_hellman_t *this,chunk_t *value)
 {
-       value->len = this->modulus_length;
-    value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->my_public);
+       value->len = this->p_len;
+    value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya);
 }
 
 /**
@@ -477,8 +483,8 @@ static status_t get_shared_secret(private_diffie_hellman_t *this, chunk_t *secre
        {
                return FAILED;
        }
-       secret->len = this->modulus_length;
-    secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->secret);
+       secret->len = this->p_len;
+    secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz);
        return SUCCESS;
 }
 
@@ -487,7 +493,7 @@ static status_t get_shared_secret(private_diffie_hellman_t *this, chunk_t *secre
  */
 static diffie_hellman_group_t get_dh_group(private_diffie_hellman_t *this)
 {
-       return this->dh_group_number;
+       return this->group;
 }
 
 /**
@@ -500,14 +506,14 @@ static status_t set_modulus(private_diffie_hellman_t *this)
        
        for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++)
        {
-               if (modulus_entries[i].group == this->dh_group_number)
+               if (modulus_entries[i].group == this->group)
                {
                        chunk_t chunk;
                        chunk.ptr = modulus_entries[i].modulus;
-                       chunk.len = modulus_entries[i].modulus_length;
-                       mpz_import(this->modulus, chunk.len, 1, 1, 1, 0, chunk.ptr);
-                       this->modulus_length = chunk.len;
-                       this->generator = modulus_entries[i].generator;
+                       chunk.len = modulus_entries[i].modulus_len;
+                       mpz_import(this->p, chunk.len, 1, 1, 1, 0, chunk.ptr);
+                       this->p_len = chunk.len;
+                       mpz_set_ui(this->g, modulus_entries[i].generator);
                        status = SUCCESS;
                        break;
                }
@@ -520,22 +526,23 @@ static status_t set_modulus(private_diffie_hellman_t *this)
  */
 static void destroy(private_diffie_hellman_t *this)
 {
-       mpz_clear(this->modulus);
-       mpz_clear(this->private);
-       mpz_clear(this->my_public);
-       mpz_clear(this->other_public);
-       mpz_clear(this->secret);
+       mpz_clear(this->p);
+       mpz_clear(this->xa);
+       mpz_clear(this->ya);
+       mpz_clear(this->yb);
+       mpz_clear(this->zz);
        free(this);
 }
 
 /*
  * Described in header.
  */
-diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number)
+diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t group)
 {
        private_diffie_hellman_t *this = malloc_thing(private_diffie_hellman_t);
        randomizer_t *randomizer;
        chunk_t random;
+       status_t status;
 
        /* public functions */
        this->public.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret;
@@ -546,39 +553,35 @@ diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number)
        this->public.destroy = (void (*)(diffie_hellman_t *)) destroy;
        
        /* private variables */
-       this->dh_group_number = dh_group_number;
-       mpz_init(this->modulus);
-       mpz_init(this->other_public);
-       mpz_init(this->my_public);
-       mpz_init(this->private);
-       mpz_init(this->secret);
+       this->group = group;
+       mpz_init(this->p);
+       mpz_init(this->yb);
+       mpz_init(this->ya);
+       mpz_init(this->xa);
+       mpz_init(this->zz);
+       mpz_init(this->g);
+       
        this->computed = FALSE;
                
-       /* set this->modulus */ 
+       /* find a modulus according to group */ 
        if (set_modulus(this) != SUCCESS)
        {
                destroy(this);
                return NULL;
        }
        randomizer = randomizer_create();
-       if (randomizer == NULL)
-       {
-               destroy(this);
-               return NULL;
-       }
-       if (randomizer->allocate_pseudo_random_bytes(randomizer, 
-                                                               this->modulus_length, &random) != SUCCESS)
+       status = randomizer->allocate_pseudo_random_bytes(
+                                                                                       randomizer, this->p_len, &random);
+       randomizer->destroy(randomizer);
+       if (status != SUCCESS)
        {
-               randomizer->destroy(randomizer);
                destroy(this);
                return NULL;
        }
-       
-       mpz_import(this->private, random.len, 1, 1, 1, 0, random.ptr);
+       mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr);
        chunk_free(&random);
-       randomizer->destroy(randomizer);
        
-       compute_public_value(this);
+       mpz_powm(this->ya, this->g, this->xa, this->p);
        
        return &this->public;
 }
index 29a2ab4..8cd06d6 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -36,7 +36,7 @@ typedef struct diffie_hellman_t diffie_hellman_t;
  *
  * See IKEv2 RFC 3.3.2 and RFC 3526.
  *
- * @ingroup transforms
+ * @ingroup crypto
  */
 enum diffie_hellman_group_t {
        MODP_NONE = 0,
@@ -56,76 +56,74 @@ enum diffie_hellman_group_t {
 extern enum_name_t *diffie_hellman_group_names;
 
 /**
- * @brief Implementation of the widely used Diffie-Hellman algorithm.
+ * @brief Implementation of the Diffie-Hellman algorithm, as in RFC2631.
  * 
  * @b Constructors:
  *  - diffie_hellman_create()
  * 
- * @ingroup transforms
+ * @ingroup crypto
  */
 struct diffie_hellman_t {
                
        /**
         * @brief Returns the shared secret of this diffie hellman exchange.
         *      
-        * @warning Space for returned secret is allocated and must be 
+        * Space for returned secret is allocated and must be 
         * freed by the caller.
         * 
-        * @param this                  calling diffie_hellman_t object
-        * @param[out] secret   shared secret will be written into this chunk
+        * @param this          calling object
+        * @param secret        shared secret will be written into this chunk
         * @return                              
-        *                                              - SUCCESS
-        *                                              - FAILED if not both DH values are set
+        *                                      - SUCCESS
+        *                                      - FAILED if not both DH values are set
         */
        status_t (*get_shared_secret) (diffie_hellman_t *this, chunk_t *secret);
        
        /**
         * @brief Sets the public value of partner.
         *      
-        * chunk gets cloned and can be destroyed afterwards.
+        * Chunk gets cloned and can be destroyed afterwards.
         * 
-        * @param this                  calling diffie_hellman_t object
-        * @param public_value  public value of partner
+        * @param this          calling object
+        * @param value         public value of partner
         */
-       void (*set_other_public_value) (diffie_hellman_t *this, chunk_t public_value);
+       void (*set_other_public_value) (diffie_hellman_t *this, chunk_t value);
        
        /**
         * @brief Gets the public value of partner.
         *      
-        * @warning Space for returned chunk is allocated and must be 
-        * freed by the caller.
+        * Space for returned chunk is allocated and must be freed by the caller.
         * 
-        * @param this                          calling diffie_hellman_t object
-        * @param[out] public_value public value of partner is stored at this location
+        * @param this          calling object
+        * @param value         public value of partner is stored at this location
         * @return                              
-        *                                                      - SUCCESS
-        *                                                      - FAILED if other public value not set
+        *                                      - SUCCESS
+        *                                      - FAILED if other public value not set
         */
-       status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *public_value);
+       status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *value);
        
        /**
-        * @brief Gets the public value of caller
+        * @brief Gets the own public value to transmit.
         *      
-        * @warning Space for returned chunk is allocated and must be 
-        * freed by the caller.
+        * Space for returned chunk is allocated and must be freed by the caller.
         * 
-        * @param this                          calling diffie_hellman_t object
-        * @param[out]                          public_value public value of caller is stored at this location
+        * @param this          calling object
+        * @param value         public value of caller is stored at this location
         */
-       void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *public_value);
+       void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *value);
        
        /**
         * @brief Get the DH group used.
         * 
-        * @param this                          calling diffie_hellman_t object
-        * @return                                      DH group set in construction
+        * @param this          calling object
+        * @return                      DH group set in construction
         */
        diffie_hellman_group_t (*get_dh_group) (diffie_hellman_t *this);
 
        /**
         * @brief Destroys an diffie_hellman_t object.
         *
-        * @param this                          diffie_hellman_t object to destroy
+        * @param this          diffie_hellman_t object to destroy
         */
        void (*destroy) (diffie_hellman_t *this);
 };
@@ -133,15 +131,14 @@ struct diffie_hellman_t {
 /**
  * @brief Creates a new diffie_hellman_t object.
  * 
- * The first diffie hellman public value gets automatically created.
- * 
- * @param dh_group_number      Diffie Hellman group number to use
+ * @param group                        Diffie Hellman group number to use
  * @return
- *                                                     - diffie_hellman_t object
- *                                                     - NULL if dh group not supported
+ *                                             - diffie_hellman_t object
+ *                                             - NULL if dh group not supported
  * 
- * @ingroup transforms
+ * @ingroup crypto
  */
-diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number);
+diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t group);
 
 #endif /*DIFFIE_HELLMAN_H_*/
+