Annotation of embedaddon/strongswan/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c, revision 1.1.1.1

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

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