X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/70dc107b6edee55270619b895f17acb66065f7ea..0bcb8184cfce875a4dde57621139dd44c433f3a5:/dh.c diff --git a/dh.c b/dh.c index 67ebd50..7a25ee1 100644 --- a/dh.c +++ b/dh.c @@ -1,40 +1,38 @@ -/*************************************************************************** - * - * Part II Project, "A secure, private IP network" - * Stephen Early - * - * - * $RCSfile: dh.c,v $ - * - * Description: Diffie-Hellman implementation - * - * Copyright: (C) Stephen Early 1995 - * - * $Revision: 1.3 $ - * - * $Date: 1996/05/16 18:38:54 $ +/* + * dh.c + */ +/* + * This file is Free Software. It was originally written for secnet. * - * $State: Exp $ + * Copyright 1995-2003 Stephen Early + * Copyright 2002-2014 Ian Jackson * - ***************************************************************************/ - -/* - * $Log: dh.c,v $ - * Revision 1.3 1996/05/16 18:38:54 sde1000 - * Removed unused hexdigits variable. + * You may redistribute secnet as a whole and/or modify it under the + * terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3, or (at your option) any + * later version. * - * Revision 1.2 1996/04/14 16:33:52 sde1000 - * Moved mpbin/mpstring functions into util.c + * You may redistribute this file and/or modify it under the terms of + * the GNU General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. * - * Revision 1.1 1996/04/14 16:21:47 sde1000 - * Initial revision + * This software 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 General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this software; if not, see + * https://www.gnu.org/licenses/gpl.html. */ #include #include +#include #include "secnet.h" +#include "magic.h" #include "util.h" struct dh { @@ -44,10 +42,10 @@ struct dh { MP_INT p,g; /* prime modulus and generator */ }; -static string_t dh_makepublic(void *sst, uint8_t *secret, uint32_t secretlen) +static int32_t dh_makepublic(void *sst, void *public, int32_t publiclen, + uint8_t *secret, int32_t secretlen) { struct dh *st=sst; - string_t r; MP_INT a, b; /* a is secret key, b is public key */ mpz_init(&a); @@ -55,18 +53,21 @@ static string_t dh_makepublic(void *sst, uint8_t *secret, uint32_t secretlen) read_mpbin(&a, secret, secretlen); - mpz_powm(&b, &st->g, &a, &st->p); + mpz_powm_sec(&b, &st->g, &a, &st->p); - r=write_mpstring(&b); + assert(mpz_sizeinbase(&b, 16) + 2 <= (size_t)publiclen); + mpz_get_str(public, 16, &b); mpz_clear(&a); mpz_clear(&b); - return r; + + return strlen(public); } -static void dh_makeshared(void *sst, uint8_t *secret, uint32_t secretlen, - string_t rempublic, uint8_t *sharedsecret, - uint32_t buflen) +static dh_makeshared_fn dh_makeshared; +static bool_t dh_makeshared(void *sst, uint8_t *secret, int32_t secretlen, + const void *public, int32_t publiclen, + uint8_t *sharedsecret, int32_t buflen) { struct dh *st=sst; MP_INT a, b, c; @@ -76,15 +77,17 @@ static void dh_makeshared(void *sst, uint8_t *secret, uint32_t secretlen, mpz_init(&c); read_mpbin(&a, secret, secretlen); - mpz_set_str(&b, rempublic, 16); + mpz_set_str(&b, public, 16); - mpz_powm(&c, &b, &a, &st->p); + mpz_powm_sec(&c, &b, &a, &st->p); write_mpbin(&c,sharedsecret,buflen); mpz_clear(&a); mpz_clear(&b); mpz_clear(&c); + + return True; } static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, @@ -92,9 +95,11 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, { struct dh *st; string_t p,g; + dict_t *dict = 0; item_t *i; + bool_t check = True; - st=safe_malloc(sizeof(*st),"dh_apply"); + NEW(st); st->cl.description="dh"; st->cl.type=CL_DH; st->cl.apply=NULL; @@ -103,40 +108,47 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, st->ops.makepublic=dh_makepublic; st->ops.makeshared=dh_makeshared; st->loc=loc; - /* We have two string arguments: the first is the modulus, and the - second is the generator. Both are in hex. */ + + /* We either have two string arguments and maybe a boolean, or a + * dictionary + */ i=list_elem(args,0); - if (i) { - if (i->type!=t_string) { - cfgfatal(i->loc,"diffie-hellman","first argument must be a " - "string\n"); - } - p=i->data.string; - if (mpz_init_set_str(&st->p,p,16)!=0) { - cfgfatal(i->loc,"diffie-hellman","\"%s\" is not a hex number " - "string\n",p); - } + if (i && i->type==t_dict) { + dict=i->data.dict; + p=dict_read_string(dict,"p",True,"diffie-hellman",loc); + g=dict_read_string(dict,"g",True,"diffie-hellman",loc); + check=dict_read_bool(dict,"check",False,"diffie-hellman",loc,True); } else { - cfgfatal(loc,"diffie-hellman","you must provide a prime modulus\n"); - } - - i=list_elem(args,1); - if (i) { - if (i->type!=t_string) { + if (!i) + cfgfatal(loc,"diffie-hellman","you must provide a prime modulus\n"); + else if (i->type!=t_string) + cfgfatal(i->loc,"diffie-hellman", + "first argument must be a string or a dictionary\n"); + p=i->data.string; + i=list_elem(args,1); + if (!i) + cfgfatal(loc,"diffie-hellman","you must provide a generator\n"); + else if (i->type!=t_string) cfgfatal(i->loc,"diffie-hellman","second argument must be a " "string\n"); - } g=i->data.string; - if (mpz_init_set_str(&st->g,g,16)!=0) { - cfgfatal(i->loc,"diffie-hellman","\"%s\" is not a hex number " - "string\n",g); + i=list_elem(args,2); + if (i) { + if (i->type!=t_bool) + cfgfatal(i->loc,"diffie-hellman", + "third argument must be boolean or omitted\n"); + check=i->data.bool; } - } else { - cfgfatal(loc,"diffie-hellman","you must provide a generator\n"); } - i=list_elem(args,2); - if (i && i->type==t_bool && i->data.bool==False) { + if (mpz_init_set_str(&st->p,p,16)!=0) + cfgfatal(loc,"diffie-hellman","\"%s\" is not a hex number " + "string\n",p); + if (mpz_init_set_str(&st->g,g,16)!=0) + cfgfatal(i->loc,"diffie-hellman","\"%s\" is not a hex number " + "string\n",g); + + if (!check) { Message(M_INFO,"diffie-hellman (%s:%d): skipping modulus " "primality check\n",loc.file,loc.line); } else { @@ -145,12 +157,35 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, cfgfatal(loc,"diffie-hellman","modulus must be a prime\n"); } } - st->ops.len=mpz_sizeinbase(&st->p,2)/8; + + size_t sz=mpz_sizeinbase(&st->p,2)/8; + if (sz>INT_MAX) { + cfgfatal(loc,"diffie-hellman","modulus far too large\n"); + } + if (mpz_cmp(&st->g,&st->p) >= 0) { + cfgfatal(loc,"diffie-hellman","generator must be less than modulus\n"); + } + + st->ops.secret_len=sz; + + st->ops.shared_len=(mpz_sizeinbase(&st->p,2)+7)/8; + /* According to the docs, mpz_sizeinbase(,256) is allowed to return + * an answer which is 1 too large. But mpz_sizeinbase(,2) isn't. */ + + st->ops.public_len=(mpz_sizeinbase(&st->p,16)+2); + + if (!dict) + st->ops.capab_bit = CAPAB_BIT_TRADZP; + else + st->ops.capab_bit = dict_read_number(dict, "capab-num", False, + "dh", loc, CAPAB_BIT_TRADZP); + if (st->ops.capab_bit > CAPAB_BIT_MAX) + cfgfatal(loc,"dh","capab-num out of range 0..%d\n", + CAPAB_BIT_MAX); return new_closure(&st->cl); } -init_module dh_module; void dh_module(dict_t *dict) { add_closure(dict,"diffie-hellman",dh_apply);