/* * Copyright (C) 2000-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ #include #include #include /* --Example-- you: X = g ^ x mod p; peer:Y = g ^ y mod p; your_key = Y ^ x mod p; his_key = X ^ y mod p; // generate our secret and the public value (X) for it X = gnutls_calc_dh_secret(&x, g, p); // now we can calculate the shared secret key = gnutls_calc_dh_key(Y, x, g, p); _gnutls_mpi_release(x); _gnutls_mpi_release(g); */ #define MAX_BITS 18000 /* returns the public value (X), and the secret (ret_x). */ int gnutls_calc_dh_secret (bigint_t* ret_y, bigint_t * ret_x, bigint_t g, bigint_t prime, unsigned int q_bits) { bigint_t e=NULL, x = NULL; unsigned int x_size; int ret; if (q_bits == 0) { x_size = _gnutls_mpi_get_nbits (prime); if (x_size > 0) x_size--; } else x_size = q_bits; if (x_size > MAX_BITS || x_size == 0) { gnutls_assert (); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } x = _gnutls_mpi_new(x_size); if (x == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto fail; } e = _gnutls_mpi_alloc_like (prime); if (e == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto fail; } do { if (_gnutls_mpi_randomize (x, x_size, GNUTLS_RND_RANDOM) == NULL) { gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; goto fail; } _gnutls_mpi_powm (e, g, x, prime); } while(_gnutls_mpi_cmp_ui(e, 1) == 0); *ret_x = x; *ret_y = e; return 0; fail: if (x) _gnutls_mpi_release (&x); if (e) _gnutls_mpi_release (&e); return ret; } /* returns f^x mod prime */ int gnutls_calc_dh_key (bigint_t *key, bigint_t f, bigint_t x, bigint_t prime) { bigint_t k, ff; unsigned int bits; int ret; ff = _gnutls_mpi_mod(f, prime); _gnutls_mpi_add_ui(ff, ff, 1); /* check if f==0,1,p-1. * or (ff=f+1) equivalently ff==1,2,p */ if ((_gnutls_mpi_cmp_ui(ff, 2) == 0) || (_gnutls_mpi_cmp_ui(ff, 1) == 0) || (_gnutls_mpi_cmp(ff,prime) == 0)) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto cleanup; } bits = _gnutls_mpi_get_nbits (prime); if (bits == 0 || bits > MAX_BITS) { gnutls_assert (); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto cleanup; } k = _gnutls_mpi_alloc_like (prime); if (k == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } _gnutls_mpi_powm (k, f, x, prime); *key = k; ret = 0; cleanup: _gnutls_mpi_release (&ff); return ret; } /*- * _gnutls_get_dh_params - Returns the DH parameters pointer * @dh_params: is an DH parameters structure, or NULL. * @func: is a callback function to receive the parameters or NULL. * @session: a gnutls session. * * This function will return the dh parameters pointer. -*/ gnutls_dh_params_t _gnutls_get_dh_params (gnutls_dh_params_t dh_params, gnutls_params_function * func, gnutls_session_t session) { gnutls_params_st params; int ret; /* if cached return the cached */ if (session->internals.params.dh_params) return session->internals.params.dh_params; if (dh_params) { session->internals.params.dh_params = dh_params; } else if (func) { ret = func (session, GNUTLS_PARAMS_DH, ¶ms); if (ret == 0 && params.type == GNUTLS_PARAMS_DH) { session->internals.params.dh_params = params.params.dh; session->internals.params.free_dh_params = params.deinit; } } return session->internals.params.dh_params; }