1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2001-2007, Tom St Denis
4 * Copyright (c) 2014, STMicroelectronics International N.V.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "tomcrypt_private.h"
31 #include <stdint.h>
32
33 /*
34 * Make a DH key [private key pair]
35 * @param prng An active PRNG state
36 * @param wprng The index for the PRNG you desire to use
37 * @param keysize The key size (octets) desired of the private key
38 * @param q If not null, then the private key is in the range
39 * [2, q-2] where q is called the subprime
40 * @param xbits If not 0, then the private key has 'xbits' bits
41 * @note The private key must always be less than p-1
42 * @param key [in/out] Where the newly created DH key will be stored
43 * g and p are provided as input in the key
44 * type, x and y are output of this function
45 * @return CRYPT_OK if successful, note: on error all allocated memory will be
46 * freed automatically.
47 */
48
dh_make_key(prng_state * prng,int wprng,void * q,int xbits,dh_key * key)49 int dh_make_key(prng_state *prng, int wprng, void *q, int xbits, dh_key *key)
50 {
51 int err = 0;
52 int key_size = 0; /* max key size, in bytes */
53 int key_size_p = 0; /* key size of p */
54 int key_size_q = 0; /* key size of p */
55 void *arg_mod = 0;
56 uint8_t *buf = 0; /* intermediate buffer to have a raw random */
57
58 /*
59 * Check the arguments
60 */
61 LTC_ARGCHK(key != NULL);
62 LTC_ARGCHK(key->base != NULL);
63 LTC_ARGCHK(key->prime != NULL);
64 err = prng_is_valid(wprng);
65 if (err != CRYPT_OK)
66 return err;
67
68 /*
69 * Set the key size and check constraints
70 */
71 if (xbits) {
72 LTC_ARGCHK((xbits % 8) == 0);
73 key_size = xbits / 8;
74 }
75 key_size_p = mp_unsigned_bin_size(key->prime);
76 if (q)
77 key_size_q = mp_unsigned_bin_size(q);
78 if (key_size) {
79 /* check the constraints */
80 LTC_ARGCHK(key_size <= key_size_p);
81 LTC_ARGCHK((q == NULL) || (key_size <= key_size_q));
82 } else {
83 if (q)
84 key_size = MIN(key_size_p, key_size_q);
85 else
86 key_size =key_size_p;
87 }
88
89 /* Set the argument we will make the modulo against to */
90 if ((q != NULL) && (key_size_q < key_size_p))
91 arg_mod = q;
92 else
93 arg_mod = key->prime;
94
95 /* initialize the key */
96 key->x = NULL;
97 key->y = NULL;
98 err = mp_init_multi(&key->x, &key->y, NULL);
99 if (err != CRYPT_OK)
100 goto error;
101
102 /* Initialize the buffer used to store the random number */
103 buf = XMALLOC(key_size);
104 if (buf == NULL) {
105 err = CRYPT_MEM;
106 goto error;
107 }
108
109 /* generate the private key in a raw-buffer */
110 if (prng_descriptor[wprng]->read(buf, key_size, prng) !=
111 (unsigned long)key_size) {
112 err = CRYPT_ERROR_READPRNG;
113 goto error;
114 }
115
116 /*
117 * Transform it as a Big Number compatible with p and q
118 */
119 err = mp_read_unsigned_bin(key->y, buf, key_size);
120 if (err != CRYPT_OK)
121 goto error;
122 err = mp_mod(key->y, arg_mod, key->x);
123 if (err != CRYPT_OK)
124 goto error;
125
126 /* generate the public key key->y */
127 err = mp_exptmod(key->base, key->x, key->prime, key->y);
128 if (err != CRYPT_OK)
129 goto error;
130
131 /* no error */
132 err = CRYPT_OK;
133
134 error:
135 if (err != CRYPT_OK)
136 mp_clear_multi(key->x, key->y, NULL);
137 if (buf)
138 XFREE(buf);
139
140 return err;
141 }
142