dh.c
Go to the documentation of this file.
1 /**
2  * @file dh.c
3  * @brief Diffie-Hellman key exchange
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Diffie-Hellman key agreement protocol allows two users to exchange a
30  * secret key over an insecure medium without any prior secrets. Refer to
31  * PKCS #3 (Diffie-Hellman Key-Agreement Standard)
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.5.2
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/crypto.h"
42 #include "pkc/dh.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (DH_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Initialize Diffie-Hellman context
51  * @param[in] context Pointer to the Diffie-Hellman context
52  **/
53 
54 void dhInit(DhContext *context)
55 {
56  //Initialize Diffie-Hellman parameters
57  dhInitParameters(&context->params);
58 
59  //Initialize private and public values
60  mpiInit(&context->xa);
61  mpiInit(&context->ya);
62  mpiInit(&context->yb);
63 }
64 
65 
66 /**
67  * @brief Release Diffie-Hellman context
68  * @param[in] context Pointer to the Diffie-Hellman context
69  **/
70 
71 void dhFree(DhContext *context)
72 {
73  //Release Diffie-Hellman parameters
74  dhFreeParameters(&context->params);
75 
76  //Release private and public values
77  mpiFree(&context->xa);
78  mpiFree(&context->ya);
79  mpiFree(&context->yb);
80 }
81 
82 
83 /**
84  * @brief Initialize Diffie-Hellman parameters
85  * @param[in] params Pointer to the Diffie-Hellman parameters
86  **/
87 
89 {
90  //Initialize prime modulus
91  mpiInit(&params->p);
92  //Initialize generator
93  mpiInit(&params->g);
94 }
95 
96 
97 /**
98  * @brief Release Diffie-Hellman parameters
99  * @param[in] params Pointer to the Diffie-Hellman parameters
100  **/
101 
103 {
104  //Release prime modulus
105  mpiFree(&params->p);
106  //Release generator
107  mpiFree(&params->g);
108 }
109 
110 
111 /**
112  * @brief Diffie-Hellman key pair generation
113  * @param[in] context Pointer to the Diffie-Hellman context
114  * @param[in] prngAlgo PRNG algorithm
115  * @param[in] prngContext Pointer to the PRNG context
116  * @return Error code
117  **/
118 
119 error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo,
120  void *prngContext)
121 {
122  error_t error;
123  uint_t k;
124 
125  //Debug message
126  TRACE_DEBUG("Generating Diffie-Hellman key pair...\r\n");
127 
128  //Get the length in bits of the prime p
129  k = mpiGetBitLength(&context->params.p);
130  //Ensure the length is valid
131  if(k == 0)
133 
134  //The private value shall be randomly generated
135  error = mpiRand(&context->xa, k, prngAlgo, prngContext);
136  //Any error to report?
137  if(error)
138  return error;
139 
140  //The private value shall be less than p
141  if(mpiComp(&context->xa, &context->params.p) >= 0)
142  {
143  //Shift value to the right
144  error = mpiShiftRight(&context->xa, 1);
145  //Any error to report?
146  if(error)
147  return error;
148  }
149 
150  //Debug message
151  TRACE_DEBUG(" Private value:\r\n");
152  TRACE_DEBUG_MPI(" ", &context->xa);
153 
154  //Calculate the corresponding public value (ya = g ^ xa mod p)
155  error = mpiExpModRegular(&context->ya, &context->params.g, &context->xa,
156  &context->params.p);
157  //Any error to report?
158  if(error)
159  return error;
160 
161  //Debug message
162  TRACE_DEBUG(" Public value:\r\n");
163  TRACE_DEBUG_MPI(" ", &context->ya);
164 
165  //Check public value
166  error = dhCheckPublicKey(context, &context->ya);
167  //Weak public value?
168  if(error)
169  return error;
170 
171  //Public value successfully generated
172  return NO_ERROR;
173 }
174 
175 
176 /**
177  * @brief Export our own public key
178  * @param[in] context Pointer to the Diffie-Hellman context
179  * @param[out] output Pointer to the octet string
180  * @param[out] written Length of the octet string, in bytes
181  * @param[in] format Output format
182  * @return Error code
183  **/
184 
185 error_t dhExportPublicKey(DhContext *context, uint8_t *output, size_t *written,
186  MpiFormat format)
187 {
188  error_t error;
189  size_t n;
190 
191  //Retrieve the length of the modulus
192  n = mpiGetByteLength(&context->params.p);
193 
194  //Export our own public key
195  error = mpiExport(&context->ya, output, n, format);
196 
197  //Check status code
198  if(!error)
199  {
200  //Return the length of the octet string
201  *written = n;
202  }
203 
204  //Return status code
205  return error;
206 }
207 
208 
209 /**
210  * @brief Import peer's public key
211  * @param[in] context Pointer to the Diffie-Hellman context
212  * @param[in] input Pointer to the octet string
213  * @param[in] length Length of the octet string, in bytes
214  * @param[in] format Input format
215  * @return Error code
216  **/
217 
218 error_t dhImportPeerPublicKey(DhContext *context, const uint8_t *input,
219  size_t length, MpiFormat format)
220 {
221  error_t error;
222 
223  //Import peer's public key
224  error = mpiImport(&context->yb, input, length, format);
225 
226  //Check status code
227  if(!error)
228  {
229  //Ensure the public key is acceptable
230  error = dhCheckPublicKey(context, &context->yb);
231  }
232 
233  //Return status code
234  return error;
235 }
236 
237 
238 /**
239  * @brief Check Diffie-Hellman public value
240  * @param[in] context Pointer to the Diffie-Hellman context
241  * @param[in] publicKey Public value to be checked
242  * @return Error code
243  **/
244 
245 error_t dhCheckPublicKey(DhContext *context, const Mpi *publicKey)
246 {
247  error_t error;
248  Mpi a;
249 
250  //Initialize multiple precision integer
251  mpiInit(&a);
252  //Precompute p - 1
253  error = mpiSubInt(&a, &context->params.p, 1);
254 
255  //Check status
256  if(!error)
257  {
258  //Reject weak public values 1 and p - 1
259  if(mpiCompInt(publicKey, 1) <= 0)
260  {
261  error = ERROR_ILLEGAL_PARAMETER;
262  }
263  else if(mpiComp(publicKey, &a) >= 0)
264  {
265  error = ERROR_ILLEGAL_PARAMETER;
266  }
267  else
268  {
269  }
270  }
271 
272  //Free previously allocated resources
273  mpiFree(&a);
274 
275  //Return status code
276  return error;
277 }
278 
279 
280 /**
281  * @brief Compute Diffie-Hellman shared secret
282  * @param[in] context Pointer to the Diffie-Hellman context
283  * @param[out] output Buffer where to store the shared secret
284  * @param[in] outputSize Size of the buffer in bytes
285  * @param[out] outputLen Length of the resulting shared secret
286  * @return Error code
287  **/
288 
289 error_t dhComputeSharedSecret(DhContext *context, uint8_t *output,
290  size_t outputSize, size_t *outputLen)
291 {
292  error_t error;
293  size_t k;
294  Mpi z;
295 
296  //Debug message
297  TRACE_DEBUG("Computing Diffie-Hellman shared secret...\r\n");
298 
299  //Get the length in octets of the prime modulus
300  k = mpiGetByteLength(&context->params.p);
301 
302  //Make sure that the output buffer is large enough
303  if(outputSize < k)
304  return ERROR_INVALID_LENGTH;
305 
306  //The multiple precision integer must be initialized before it can be used
307  mpiInit(&z);
308 
309  //Start of exception handling block
310  do
311  {
312  //Calculate the shared secret key (k = yb ^ xa mod p)
313  error = mpiExpModRegular(&z, &context->yb, &context->xa,
314  &context->params.p);
315  //Any error to report?
316  if(error)
317  break;
318 
319  //Convert the resulting integer to an octet string
320  error = mpiExport(&z, output, k, MPI_FORMAT_BIG_ENDIAN);
321  //Conversion failed?
322  if(error)
323  break;
324 
325  //Length of the resulting shared secret
326  *outputLen = k;
327 
328  //Debug message
329  TRACE_DEBUG(" Shared secret (%" PRIuSIZE " bytes):\r\n", *outputLen);
330  TRACE_DEBUG_ARRAY(" ", output, *outputLen);
331 
332  //End of exception handling block
333  } while(0);
334 
335  //Release previously allocated resources
336  mpiFree(&z);
337 
338  //Return status code
339  return error;
340 }
341 
342 #endif
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:102
#define PrngAlgo
Definition: crypto.h:980
@ ERROR_ILLEGAL_PARAMETER
Definition: error.h:244
error_t mpiShiftRight(Mpi *r, uint_t n)
Right shift operation.
Definition: mpi.c:1310
error_t mpiRand(Mpi *r, uint_t length, const PrngAlgo *prngAlgo, void *prngContext)
Generate a random value.
Definition: mpi.c:598
error_t mpiSubInt(Mpi *r, const Mpi *a, mpi_sword_t b)
Subtract an integer from a multiple precision integer.
Definition: mpi.c:1018
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
Mpi yb
Peer's public value.
Definition: dh.h:64
Diffie-Hellman context.
Definition: dh.h:60
error_t dhComputeSharedSecret(DhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute Diffie-Hellman shared secret.
Definition: dh.c:289
Diffie-Hellman key exchange.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:43
DhParameters params
Definition: dh.h:61
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:712
Mpi xa
One's own private value.
Definition: dh.h:62
void dhFree(DhContext *context)
Release Diffie-Hellman context.
Definition: dh.c:71
@ ERROR_INVALID_LENGTH
Definition: error.h:111
Mpi p
Prime modulus.
Definition: dh.h:50
General definitions for cryptographic algorithms.
error_t dhCheckPublicKey(DhContext *context, const Mpi *publicKey)
Check Diffie-Hellman public value.
Definition: dh.c:245
error_t dhImportPeerPublicKey(DhContext *context, const uint8_t *input, size_t length, MpiFormat format)
Import peer's public key.
Definition: dh.c:218
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:809
uint8_t length
Definition: tcp.h:375
error_t dhExportPublicKey(DhContext *context, uint8_t *output, size_t *written, MpiFormat format)
Export our own public key.
Definition: dh.c:185
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
uint8_t z
Definition: dns_common.h:193
MpiFormat
MPI import/export format.
Definition: mpi.h:91
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
uint8_t n
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
Mpi g
Generator.
Definition: dh.h:51
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:358
error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
Diffie-Hellman key pair generation.
Definition: dh.c:119
Mpi ya
One's own public value.
Definition: dh.h:63
int_t mpiCompInt(const Mpi *a, mpi_sword_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:429
Diffie-Hellman parameters.
Definition: dh.h:49
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define TRACE_DEBUG_MPI(p, a)
Definition: debug.h:122
void dhFreeParameters(DhParameters *params)
Release Diffie-Hellman parameters.
Definition: dh.c:102
void dhInit(DhContext *context)
Initialize Diffie-Hellman context.
Definition: dh.c:54
@ NO_ERROR
Success.
Definition: error.h:44
error_t mpiExpModRegular(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation (regular calculation)
Debugging facilities.
void dhInitParameters(DhParameters *params)
Initialize Diffie-Hellman parameters.
Definition: dh.c:88
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:215
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64