| // SPDX-License-Identifier: BSD-2-Clause |
| /* |
| * Copyright (c) 2001-2007, Tom St Denis |
| * Copyright (c) 2014, STMicroelectronics International N.V. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "tomcrypt_private.h" |
| #include <stdint.h> |
| |
| /* |
| * Make a DH key [private key pair] |
| * @param prng An active PRNG state |
| * @param wprng The index for the PRNG you desire to use |
| * @param keysize The key size (octets) desired of the private key |
| * @param q If not null, then the private key is in the range |
| * [2, q-2] where q is called the subprime |
| * @param xbits If not 0, then the private key has 'xbits' bits |
| * @note The private key must always be less than p-1 |
| * @param key [in/out] Where the newly created DH key will be stored |
| * g and p are provided as input in the key |
| * type, x and y are output of this function |
| * @return CRYPT_OK if successful, note: on error all allocated memory will be |
| * freed automatically. |
| */ |
| |
| int dh_make_key(prng_state *prng, int wprng, void *q, int xbits, dh_key *key) |
| { |
| const int limit = 500; /* number of tries */ |
| int err, i; |
| int key_size = 0; /* max key size, in bytes */ |
| int key_size_p = 0; /* key size of p */ |
| int key_size_q = 0; /* key size of p */ |
| void *arg_mod; |
| uint8_t *buf = 0; /* intermediate buffer to have a raw random */ |
| int found = 0; |
| |
| /* |
| * Check the arguments |
| */ |
| LTC_ARGCHK(key != NULL); |
| LTC_ARGCHK(key->base != NULL); |
| LTC_ARGCHK(key->prime != NULL); |
| err = prng_is_valid(wprng); |
| if (err != CRYPT_OK) |
| return err; |
| |
| /* |
| * Set the key size and check constraints |
| */ |
| if (xbits) { |
| LTC_ARGCHK((xbits % 8) == 0); |
| key_size = xbits / 8; |
| } |
| key_size_p = mp_unsigned_bin_size(key->prime); |
| if (q) |
| key_size_q = mp_unsigned_bin_size(q); |
| if (key_size) { |
| /* check the constraints */ |
| LTC_ARGCHK(key_size <= key_size_p); |
| LTC_ARGCHK((q == NULL) || (key_size <= key_size_q)); |
| } else { |
| if (q) |
| key_size = MIN(key_size_p, key_size_q); |
| else |
| key_size =key_size_p; |
| } |
| |
| /* Set the argument we will make the modulo against to */ |
| if ((q != NULL) && (key_size_q < key_size_p)) |
| arg_mod = q; |
| else |
| arg_mod = key->prime; |
| |
| /* initialize the key */ |
| key->x = NULL; |
| key->y = NULL; |
| err = mp_init_multi(&key->x, &key->y, NULL); |
| if (err != CRYPT_OK) |
| goto error; |
| |
| /* Initialize the buffer used to store the random number */ |
| buf = XMALLOC(key_size); |
| if (buf == NULL) { |
| err = CRYPT_MEM; |
| goto error; |
| } |
| |
| for (i = 0; (i < limit) && (!found); i++) { |
| /* generate the private key in a raw-buffer */ |
| if (prng_descriptor[wprng]->read(buf, key_size, prng) != |
| (unsigned long)key_size) { |
| err = CRYPT_ERROR_READPRNG; |
| goto error; |
| } |
| |
| /* make sure it is on the right number of bits */ |
| if (xbits) |
| buf[0] |= 0x80; |
| |
| /* transform it as a Big Number */ |
| err = mp_read_unsigned_bin(key->x, buf, key_size); |
| if (err != CRYPT_OK) |
| goto error; |
| |
| /* |
| * Transform it as a Big Number compatible with p and q |
| */ |
| err = mp_read_unsigned_bin(key->y, buf, key_size); |
| if (err != CRYPT_OK) |
| goto error; |
| err = mp_mod(key->y, arg_mod, key->x); |
| if (err != CRYPT_OK) |
| goto error; |
| |
| /* |
| * Check the constraints |
| * - x < p is ok by construction |
| * - x < q-1: |
| * - x contains xbits |
| */ |
| if (xbits) { |
| if (mp_count_bits(key->x) != xbits) |
| continue; |
| } |
| |
| /* we found a suitable private key key->x */ |
| found = 1; |
| } |
| |
| if (!found) { |
| /* key is not found */ |
| err = CRYPT_ERROR; |
| goto error; |
| } |
| |
| /* generate the public key key->y */ |
| err = mp_exptmod(key->base, key->x, key->prime, key->y); |
| if (err != CRYPT_OK) |
| goto error; |
| |
| /* no error */ |
| err = CRYPT_OK; |
| |
| error: |
| if (err != CRYPT_OK) |
| mp_clear_multi(key->x, key->y, NULL); |
| if (buf) |
| XFREE(buf); |
| |
| return err; |
| } |