From a1e8b839a9487bac03d25ed5257e5334fb2027de Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sun, 4 Oct 2009 18:18:31 +0000 Subject: [PATCH] [egg] Add DH functions for use by IPC. --- egg/Makefile.am | 1 + egg/egg-dh.c | 144 ++++++++++++++++++++++++++++++++++++++ egg/egg-dh.h | 35 +++++++++ egg/tests/Makefile.am | 1 + egg/tests/test-data/dh-params.pem | 5 ++ egg/tests/unit-test-dh.c | 89 +++++++++++++++++++++++ 6 files changed, 275 insertions(+) create mode 100644 egg/egg-dh.c create mode 100644 egg/egg-dh.h create mode 100644 egg/tests/test-data/dh-params.pem create mode 100644 egg/tests/unit-test-dh.c diff --git a/egg/Makefile.am b/egg/Makefile.am index f3aec93..a0bf0db 100644 --- a/egg/Makefile.am +++ b/egg/Makefile.am @@ -22,6 +22,7 @@ libegg_la_SOURCES = \ egg-asn1.c egg-asn1.h \ egg-buffer.c egg-buffer.h \ egg-cleanup.c egg-cleanup.h \ + egg-dh.c egg-dh.h \ egg-hex.c egg-hex.h \ egg-libgcrypt.c egg-libgcrypt.h \ egg-oid.c egg-oid.h \ diff --git a/egg/egg-dh.c b/egg/egg-dh.c new file mode 100644 index 0000000..bc14f36 --- /dev/null +++ b/egg/egg-dh.c @@ -0,0 +1,144 @@ +/* + * gnome-keyring + * + * Copyright (C) 2009 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "egg-asn1.h" +#include "egg-dh.h" +#include "egg-openssl.h" + +gboolean +egg_dh_gen_secret (gcry_mpi_t p, gcry_mpi_t g, + gcry_mpi_t *X, gcry_mpi_t *x) +{ + gint bits; + + g_return_val_if_fail (g, FALSE); + g_return_val_if_fail (p, FALSE); + g_return_val_if_fail (X, FALSE); + g_return_val_if_fail (x, FALSE); + + /* Secret key value must be less than half of p */ + bits = gcry_mpi_get_nbits (p) - 1; + g_return_val_if_fail (bits >= 0, FALSE); + + /* + * Generate a strong random number of bits, and not zero. + * gcry_mpi_randomize bumps up to the next byte. Since we + * need to have a value less than half of p, we make sure + * we bump down. + */ + *x = gcry_mpi_snew (bits); + g_return_val_if_fail (*x, FALSE); + while (gcry_mpi_cmp_ui (*x, 0) == 0) + gcry_mpi_randomize (*x, (bits / 8) * 8, GCRY_STRONG_RANDOM); + + *X = gcry_mpi_new (bits); + g_return_val_if_fail (*X, FALSE); + gcry_mpi_powm (*X, g, *x, p); + + return TRUE; +} + +gboolean +egg_dh_gen_key (gcry_mpi_t Y, gcry_mpi_t x, + gcry_mpi_t p, gcry_mpi_t *k) +{ + gint bits; + + g_return_val_if_fail (Y, FALSE); + g_return_val_if_fail (x, FALSE); + g_return_val_if_fail (p, FALSE); + g_return_val_if_fail (k, FALSE); + + bits = gcry_mpi_get_nbits (p); + g_return_val_if_fail (bits >= 0, FALSE); + + *k = gcry_mpi_snew (bits); + g_return_val_if_fail (*k, FALSE); + gcry_mpi_powm (*k, Y, x, p); + + return TRUE; +} + +typedef struct _Parameters { + gcry_mpi_t p; + gcry_mpi_t g; +} Parameters; + +static gboolean +parse_der_pkcs3 (const guchar *data, gsize n_data, Parameters *params) +{ + ASN1_TYPE asn; + guchar *buf_p, *buf_g; + gsize n_buf_p, n_buf_g; + gcry_error_t gcry; + + asn = egg_asn1_decode ("PK.DHParameter", data, n_data); + if (!asn) + return FALSE; + + buf_p = egg_asn1_read_value (asn, "prime", &n_buf_p, (EggAllocator)g_realloc); + buf_g = egg_asn1_read_value (asn, "base", &n_buf_g, (EggAllocator)g_realloc); + g_return_val_if_fail (buf_p && buf_g, FALSE); + gcry = gcry_mpi_scan (¶ms->p, GCRYMPI_FMT_STD, buf_p, n_buf_p, &n_buf_p); + g_return_val_if_fail (gcry == 0, FALSE); + gcry = gcry_mpi_scan (¶ms->g, GCRYMPI_FMT_STD, buf_g, n_buf_g, &n_buf_g); + g_return_val_if_fail (gcry == 0, FALSE); + + g_free (buf_p); + g_free (buf_g); + return TRUE; +} + +static void +parse_openssl_pkcs3 (GQuark type, const guchar *data, gsize n_data, + GHashTable *headers, gpointer user_data) +{ + Parameters *params = user_data; + + /* Only parse the first one */ + if (params->p != NULL) + return; + + if (g_quark_try_string ("DH PARAMETERS") == type) + parse_der_pkcs3 (data, n_data, params); +} + +gboolean +egg_dh_parse_pkcs3 (const guchar *data, gsize n_data, gcry_mpi_t *p, gcry_mpi_t *g) +{ + Parameters params; + + g_return_val_if_fail (data, FALSE); + g_return_val_if_fail (p, FALSE); + g_return_val_if_fail (g, FALSE); + + memset (¶ms, 0, sizeof (params)); + if (!parse_der_pkcs3 (data, n_data, ¶ms)) + egg_openssl_pem_parse (data, n_data, parse_openssl_pkcs3, ¶ms); + + if (!params.p || !params.g) + return FALSE; + *p = params.p; + *g = params.g; + return TRUE; +} diff --git a/egg/egg-dh.h b/egg/egg-dh.h new file mode 100644 index 0000000..aa92808 --- /dev/null +++ b/egg/egg-dh.h @@ -0,0 +1,35 @@ +/* + * gnome-keyring + * + * Copyright (C) 2009 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef EGG_DH_H_ +#define EGG_DH_H_ + +#include + +#include + +gboolean egg_dh_gen_secret (gcry_mpi_t p, gcry_mpi_t g, gcry_mpi_t *X, gcry_mpi_t *x); + +gboolean egg_dh_gen_key (gcry_mpi_t Y, gcry_mpi_t x, gcry_mpi_t p, gcry_mpi_t *k); + +gboolean egg_dh_parse_pkcs3 (const guchar *data, gsize n_data, gcry_mpi_t *p, gcry_mpi_t *g); + +#endif /* EGG_DH_H_ */ diff --git a/egg/tests/Makefile.am b/egg/tests/Makefile.am index a7fa687..f205fae 100644 --- a/egg/tests/Makefile.am +++ b/egg/tests/Makefile.am @@ -10,6 +10,7 @@ UNIT_AUTO = \ unit-test-secmem.c \ unit-test-symkey.c \ unit-test-openssl.c \ + unit-test-dh.c asn1-def-test.h UNIT_PROMPT = diff --git a/egg/tests/test-data/dh-params.pem b/egg/tests/test-data/dh-params.pem new file mode 100644 index 0000000..cc0afd8 --- /dev/null +++ b/egg/tests/test-data/dh-params.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAOmZHLx3BXvrPoFlAl6DOHIr2wApepEOpEESnqhO0JGvnaVWgaGS5+fC +g/9vqexageA6jAmZ9msZ34C+hn0KebHbPkKufsH8oFeInz7WZuhsPCSKpHyOaZmX +GDx6gJMkLA10HOXU4bqZy1rOiVxTuS2bn+aw2CA7WoKGVnuOnCozAgEC +-----END DH PARAMETERS----- diff --git a/egg/tests/unit-test-dh.c b/egg/tests/unit-test-dh.c new file mode 100644 index 0000000..a190da3 --- /dev/null +++ b/egg/tests/unit-test-dh.c @@ -0,0 +1,89 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* unit-test-dh.c: Test egg-dh.c + + Copyright (C) 2009 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome 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. + + Author: Stef Walter +*/ + +#include +#include +#include + +#include "run-auto-test.h" + +#include "egg-dh.h" + +#include + +DEFINE_TEST(dh_parse_pkcs3) +{ + gcry_mpi_t p, g; + guchar *data; + gsize n_data; + gboolean ret; + + data = test_read_testdata ("dh-params.pem", &n_data); + ret = egg_dh_parse_pkcs3 (data, n_data, &p, &g); + g_assert (ret == TRUE); + g_assert (gcry_mpi_get_nbits (p) == 1024); + + gcry_mpi_release (p); + gcry_mpi_release (g); + g_free (data); +} + +DEFINE_TEST(dh_perform) +{ + guchar *data; + gsize n_data; + gcry_mpi_t p, g; + gcry_mpi_t x1, X1, k1; + gcry_mpi_t x2, X2, k2; + gboolean ret; + + /* Load up the parameters */ + data = test_read_testdata ("dh-params.pem", &n_data); + if (!egg_dh_parse_pkcs3 (data, n_data, &p, &g)) + g_assert_not_reached (); + g_free (data); + + /* Generate secrets */ + ret = egg_dh_gen_secret (p, g, &X1, &x1); + g_assert (ret); + ret = egg_dh_gen_secret (p, g, &X2, &x2); + g_assert (ret); + + /* Calculate keys */ + ret = egg_dh_gen_key (X2, x1, p, &k1); + g_assert (ret); + ret = egg_dh_gen_key (X1, x2, p, &k2); + g_assert (ret); + + /* Keys must be the same */ + g_assert (gcry_mpi_cmp (k1, k2) == 0); + + gcry_mpi_release (p); + gcry_mpi_release (g); + gcry_mpi_release (x1); + gcry_mpi_release (X1); + gcry_mpi_release (k1); + gcry_mpi_release (x2); + gcry_mpi_release (X2); + gcry_mpi_release (k2); +} -- 2.7.4