Annotation of embedaddon/strongswan/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 1998-2002  D. Hugh Redelmeier.
                      3:  * Copyright (C) 1999, 2000, 2001  Henry Spencer.
                      4:  * Copyright (C) 2010 Tobias Brunner
                      5:  * Copyright (C) 2005-2008 Martin Willi
                      6:  * Copyright (C) 2005 Jan Hutter
                      7:  * HSR Hochschule fuer Technik Rapperswil
                      8:  *
                      9:  * This program is free software; you can redistribute it and/or modify it
                     10:  * under the terms of the GNU General Public License as published by the
                     11:  * Free Software Foundation; either version 2 of the License, or (at your
                     12:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     13:  *
                     14:  * This program is distributed in the hope that it will be useful, but
                     15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     16:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     17:  * for more details.
                     18:  */
                     19: 
                     20: #include <gmp.h>
                     21: 
                     22: #include "gmp_diffie_hellman.h"
                     23: 
                     24: #include <utils/debug.h>
                     25: 
                     26: #ifdef HAVE_MPZ_POWM_SEC
                     27: # undef mpz_powm
                     28: # define mpz_powm mpz_powm_sec
                     29: #endif
                     30: 
                     31: typedef struct private_gmp_diffie_hellman_t private_gmp_diffie_hellman_t;
                     32: 
                     33: /**
                     34:  * Private data of an gmp_diffie_hellman_t object.
                     35:  */
                     36: struct private_gmp_diffie_hellman_t {
                     37:        /**
                     38:         * Public gmp_diffie_hellman_t interface.
                     39:         */
                     40:        gmp_diffie_hellman_t public;
                     41: 
                     42:        /**
                     43:         * Diffie Hellman group number.
                     44:         */
                     45:        diffie_hellman_group_t group;
                     46: 
                     47:        /*
                     48:         * Generator value.
                     49:         */
                     50:        mpz_t g;
                     51: 
                     52:        /**
                     53:         * My private value.
                     54:         */
                     55:        mpz_t xa;
                     56: 
                     57:        /**
                     58:         * My public value.
                     59:         */
                     60:        mpz_t ya;
                     61: 
                     62:        /**
                     63:         * Other public value.
                     64:         */
                     65:        mpz_t yb;
                     66: 
                     67:        /**
                     68:         * Shared secret.
                     69:         */
                     70:        mpz_t zz;
                     71: 
                     72:        /**
                     73:         * Modulus.
                     74:         */
                     75:        mpz_t p;
                     76: 
                     77:        /**
                     78:         * Modulus length.
                     79:         */
                     80:        size_t p_len;
                     81: 
                     82:        /**
                     83:         * True if shared secret is computed and stored in my_public_value.
                     84:         */
                     85:        bool computed;
                     86: };
                     87: 
                     88: METHOD(diffie_hellman_t, set_other_public_value, bool,
                     89:        private_gmp_diffie_hellman_t *this, chunk_t value)
                     90: {
                     91:        mpz_t p_min_1;
                     92: 
                     93:        if (!diffie_hellman_verify_value(this->group, value))
                     94:        {
                     95:                return FALSE;
                     96:        }
                     97: 
                     98:        mpz_init(p_min_1);
                     99:        mpz_sub_ui(p_min_1, this->p, 1);
                    100: 
                    101:        mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr);
                    102: 
                    103:        /* check public value:
                    104:         * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
                    105:         * 2. a public value larger or equal the modulus is invalid */
                    106:        if (mpz_cmp_ui(this->yb, 1) > 0 &&
                    107:                mpz_cmp(this->yb, p_min_1) < 0)
                    108:        {
                    109: #ifdef EXTENDED_DH_TEST
                    110:                /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */
                    111:                mpz_t q, one;
                    112:                diffie_hellman_params_t *params;
                    113: 
                    114:                mpz_init(q);
                    115:                mpz_init(one);
                    116: 
                    117:                params = diffie_hellman_get_params(this->group);
                    118:                if (!params->subgroup.len)
                    119:                {
                    120:                        mpz_fdiv_q_2exp(q, p_min_1, 1);
                    121:                }
                    122:                else
                    123:                {
                    124:                        mpz_import(q, params->subgroup.len, 1, 1, 1, 0, params->subgroup.ptr);
                    125:                }
                    126:                mpz_powm(one, this->yb, q, this->p);
                    127:                mpz_clear(q);
                    128:                if (mpz_cmp_ui(one, 1) == 0)
                    129:                {
                    130:                        mpz_powm(this->zz, this->yb, this->xa, this->p);
                    131:                        this->computed = TRUE;
                    132:                }
                    133:                else
                    134:                {
                    135:                        DBG1(DBG_LIB, "public DH value verification failed:"
                    136:                                 " y ^ q mod p != 1");
                    137:                }
                    138:                mpz_clear(one);
                    139: #else
                    140:                mpz_powm(this->zz, this->yb, this->xa, this->p);
                    141:                this->computed = TRUE;
                    142: #endif
                    143:        }
                    144:        else
                    145:        {
                    146:                DBG1(DBG_LIB, "public DH value verification failed:"
                    147:                         " y < 2 || y > p - 1 ");
                    148:        }
                    149:        mpz_clear(p_min_1);
                    150:        return this->computed;
                    151: }
                    152: 
                    153: METHOD(diffie_hellman_t, get_my_public_value, bool,
                    154:        private_gmp_diffie_hellman_t *this,chunk_t *value)
                    155: {
                    156:        value->len = this->p_len;
                    157:        value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya);
                    158:        if (value->ptr == NULL)
                    159:        {
                    160:                value->len = 0;
                    161:        }
                    162:        return TRUE;
                    163: }
                    164: 
                    165: METHOD(diffie_hellman_t, set_private_value, bool,
                    166:        private_gmp_diffie_hellman_t *this, chunk_t value)
                    167: {
                    168:        mpz_import(this->xa, value.len, 1, 1, 1, 0, value.ptr);
                    169:        mpz_powm(this->ya, this->g, this->xa, this->p);
                    170:        this->computed = FALSE;
                    171:        return TRUE;
                    172: }
                    173: 
                    174: METHOD(diffie_hellman_t, get_shared_secret, bool,
                    175:        private_gmp_diffie_hellman_t *this, chunk_t *secret)
                    176: {
                    177:        if (!this->computed)
                    178:        {
                    179:                return FALSE;
                    180:        }
                    181:        secret->len = this->p_len;
                    182:        secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz);
                    183:        if (secret->ptr == NULL)
                    184:        {
                    185:                return FALSE;
                    186:        }
                    187:        return TRUE;
                    188: }
                    189: 
                    190: METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
                    191:        private_gmp_diffie_hellman_t *this)
                    192: {
                    193:        return this->group;
                    194: }
                    195: 
                    196: METHOD(diffie_hellman_t, destroy, void,
                    197:        private_gmp_diffie_hellman_t *this)
                    198: {
                    199:        mpz_clear(this->p);
                    200:        mpz_clear(this->xa);
                    201:        mpz_clear(this->ya);
                    202:        mpz_clear(this->yb);
                    203:        mpz_clear(this->zz);
                    204:        mpz_clear(this->g);
                    205:        free(this);
                    206: }
                    207: 
                    208: /**
                    209:  * Generic internal constructor
                    210:  */
                    211: static gmp_diffie_hellman_t *create_generic(diffie_hellman_group_t group,
                    212:                                                                                        size_t exp_len, chunk_t g, chunk_t p)
                    213: {
                    214:        private_gmp_diffie_hellman_t *this;
                    215:        chunk_t random;
                    216:        rng_t *rng;
                    217: 
                    218:        INIT(this,
                    219:                .public = {
                    220:                        .dh = {
                    221:                                .get_shared_secret = _get_shared_secret,
                    222:                                .set_other_public_value = _set_other_public_value,
                    223:                                .get_my_public_value = _get_my_public_value,
                    224:                                .set_private_value = _set_private_value,
                    225:                                .get_dh_group = _get_dh_group,
                    226:                                .destroy = _destroy,
                    227:                        },
                    228:                },
                    229:                .group = group,
                    230:                .p_len = p.len,
                    231:        );
                    232: 
                    233:        mpz_init(this->p);
                    234:        mpz_init(this->yb);
                    235:        mpz_init(this->ya);
                    236:        mpz_init(this->xa);
                    237:        mpz_init(this->zz);
                    238:        mpz_init(this->g);
                    239:        mpz_import(this->g, g.len, 1, 1, 1, 0, g.ptr);
                    240:        mpz_import(this->p, p.len, 1, 1, 1, 0, p.ptr);
                    241: 
                    242:        rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
                    243:        if (!rng)
                    244:        {
                    245:                DBG1(DBG_LIB, "no RNG found for quality %N", rng_quality_names,
                    246:                         RNG_STRONG);
                    247:                destroy(this);
                    248:                return NULL;
                    249:        }
                    250:        if (!rng->allocate_bytes(rng, exp_len, &random))
                    251:        {
                    252:                DBG1(DBG_LIB, "failed to allocate DH secret");
                    253:                rng->destroy(rng);
                    254:                destroy(this);
                    255:                return NULL;
                    256:        }
                    257:        rng->destroy(rng);
                    258: 
                    259:        if (exp_len == this->p_len)
                    260:        {
                    261:                /* achieve bitsof(p)-1 by setting MSB to 0 */
                    262:                *random.ptr &= 0x7F;
                    263:        }
                    264:        mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr);
                    265:        chunk_clear(&random);
                    266:        DBG2(DBG_LIB, "size of DH secret exponent: %u bits",
                    267:                 mpz_sizeinbase(this->xa, 2));
                    268: 
                    269:        mpz_powm(this->ya, this->g, this->xa, this->p);
                    270: 
                    271:        return &this->public;
                    272: }
                    273: 
                    274: /*
                    275:  * Described in header
                    276:  */
                    277: gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group)
                    278: {
                    279:        diffie_hellman_params_t *params;
                    280: 
                    281:        params = diffie_hellman_get_params(group);
                    282:        if (!params)
                    283:        {
                    284:                return NULL;
                    285:        }
                    286:        return create_generic(group, params->exp_len,
                    287:                                                  params->generator, params->prime);
                    288: }
                    289: 
                    290: /*
                    291:  * Described in header
                    292:  */
                    293: gmp_diffie_hellman_t *gmp_diffie_hellman_create_custom(
                    294:                                                                                        diffie_hellman_group_t group, ...)
                    295: {
                    296:        if (group == MODP_CUSTOM)
                    297:        {
                    298:                chunk_t g, p;
                    299: 
                    300:                VA_ARGS_GET(group, g, p);
                    301:                return create_generic(MODP_CUSTOM, p.len, g, p);
                    302:        }
                    303:        return NULL;
                    304: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>