/*
* 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
*
*/
#include <gmp.h>
-#include <stdio.h>
#include "diffie_hellman.h"
/*
* Length of modulus in bytes.
*/
- size_t modulus_length;
+ size_t modulus_len;
/*
* Generator value.
/**
* 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.
};
/**
- * 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);
}
/**
{
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);
}
/**
{
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;
}
*/
static diffie_hellman_group_t get_dh_group(private_diffie_hellman_t *this)
{
- return this->dh_group_number;
+ return this->group;
}
/**
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;
}
*/
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;
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;
}
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
*
* See IKEv2 RFC 3.3.2 and RFC 3526.
*
- * @ingroup transforms
+ * @ingroup crypto
*/
enum diffie_hellman_group_t {
MODP_NONE = 0,
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);
};
/**
* @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_*/
+