Return to gmp_diffie_hellman.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / gmp |
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: }