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-2019 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 1.9.6
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  mpiInit(&context->params.p);
58  mpiInit(&context->params.g);
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  mpiFree(&context->params.p);
75  mpiFree(&context->params.g);
76  //Release private and public values
77  mpiFree(&context->xa);
78  mpiFree(&context->ya);
79  mpiFree(&context->yb);
80 }
81 
82 
83 /**
84  * @brief Diffie-Hellman key pair generation
85  * @param[in] context Pointer to the Diffie-Hellman context
86  * @param[in] prngAlgo PRNG algorithm
87  * @param[in] prngContext Pointer to the PRNG context
88  * @return Error code
89  **/
90 
92  const PrngAlgo *prngAlgo, void *prngContext)
93 {
94  error_t error;
95  uint_t k;
96 
97  //Debug message
98  TRACE_DEBUG("Generating Diffie-Hellman key pair...\r\n");
99 
100  //Get the length in bits of the prime p
101  k = mpiGetBitLength(&context->params.p);
102  //Ensure the length is valid
103  if(k == 0)
105 
106  //The private value shall be randomly generated
107  error = mpiRand(&context->xa, k, prngAlgo, prngContext);
108  //Any error to report?
109  if(error)
110  return error;
111 
112  //The private value shall be less than p
113  if(mpiComp(&context->xa, &context->params.p) >= 0)
114  {
115  //Shift value to the right
116  error = mpiShiftRight(&context->xa, 1);
117  //Any error to report?
118  if(error)
119  return error;
120  }
121 
122  //Debug message
123  TRACE_DEBUG(" Private value:\r\n");
124  TRACE_DEBUG_MPI(" ", &context->xa);
125 
126  //Calculate the corresponding public value (ya = g ^ xa mod p)
127  error = mpiExpMod(&context->ya, &context->params.g, &context->xa, &context->params.p);
128  //Any error to report?
129  if(error)
130  return error;
131 
132  //Debug message
133  TRACE_DEBUG(" Public value:\r\n");
134  TRACE_DEBUG_MPI(" ", &context->ya);
135 
136  //Check public value
137  error = dhCheckPublicKey(&context->params, &context->ya);
138  //Weak public value?
139  if(error)
140  return error;
141 
142  //Public value successfully generated
143  return NO_ERROR;
144 }
145 
146 
147 /**
148  * @brief Check Diffie-Hellman public value
149  * @param[in] params Pointer to the Diffie-Hellman parameters
150  * @param[in] publicKey Public value to be checked
151  * @return Error code
152  **/
153 
154 error_t dhCheckPublicKey(DhParameters *params, const Mpi *publicKey)
155 {
156  error_t error;
157  Mpi a;
158 
159  //Initialize multiple precision integer
160  mpiInit(&a);
161  //Precompute p - 1
162  error = mpiSubInt(&a, &params->p, 1);
163 
164  //Check status
165  if(!error)
166  {
167  //Reject weak public values 1 and p - 1
168  if(mpiCompInt(publicKey, 1) <= 0)
169  error = ERROR_ILLEGAL_PARAMETER;
170  else if(mpiComp(publicKey, &a) >= 0)
171  error = ERROR_ILLEGAL_PARAMETER;
172  }
173 
174  //Free previously allocated resources
175  mpiFree(&a);
176  //Return status code
177  return error;
178 }
179 
180 
181 /**
182  * @brief Compute Diffie-Hellman shared secret
183  * @param[in] context Pointer to the Diffie-Hellman context
184  * @param[out] output Buffer where to store the shared secret
185  * @param[in] outputSize Size of the buffer in bytes
186  * @param[out] outputLen Length of the resulting shared secret
187  * @return Error code
188  **/
189 
191  uint8_t *output, size_t outputSize, size_t *outputLen)
192 {
193  error_t error;
194  size_t k;
195  Mpi z;
196 
197  //Debug message
198  TRACE_DEBUG("Computing Diffie-Hellman shared secret...\r\n");
199 
200  //Get the length in octets of the prime modulus
201  k = mpiGetByteLength(&context->params.p);
202 
203  //Make sure that the output buffer is large enough
204  if(outputSize < k)
205  return ERROR_INVALID_LENGTH;
206 
207  //The multiple precision integer must be initialized before it can be used
208  mpiInit(&z);
209 
210  //Start of exception handling block
211  do
212  {
213  //Calculate the shared secret key (k = yb ^ xa mod p)
214  error = mpiExpMod(&z, &context->yb, &context->xa, &context->params.p);
215  //Any error to report?
216  if(error)
217  break;
218 
219  //Convert the resulting integer to an octet string
220  error = mpiWriteRaw(&z, output, k);
221  //Conversion failed?
222  if(error)
223  break;
224 
225  //Length of the resulting shared secret
226  *outputLen = k;
227 
228  //Debug message
229  TRACE_DEBUG(" Shared secret (%" PRIuSIZE " bytes):\r\n", *outputLen);
230  TRACE_DEBUG_ARRAY(" ", output, *outputLen);
231 
232  //End of exception handling block
233  } while(0);
234 
235  //Release previously allocated resources
236  mpiFree(&z);
237  //Return status code
238  return error;
239 }
240 
241 #endif
error_t mpiSubInt(Mpi *r, const Mpi *a, int_t b)
Subtract an integer from a multiple precision integer.
Definition: mpi.c:818
uint8_t a
Definition: ndp.h:410
Arbitrary precision integer.
Definition: mpi.h:69
Common interface for pseudo-random number generators.
Definition: crypto.h:1168
@ ERROR_ILLEGAL_PARAMETER
Definition: error.h:237
error_t dhCheckPublicKey(DhParameters *params, const Mpi *publicKey)
Check Diffie-Hellman public value.
Definition: dh.c:154
#define mpiWriteRaw(a, data, length)
Definition: crypto_legacy.h:36
error_t mpiShiftRight(Mpi *r, uint_t n)
Right shift operation.
Definition: mpi.c:1073
error_t mpiRand(Mpi *r, uint_t length, const PrngAlgo *prngAlgo, void *prngContext)
Generate a random value.
Definition: mpi.c:468
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:59
error_t dhComputeSharedSecret(DhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute Diffie-Hellman shared secret.
Definition: dh.c:190
Diffie-Hellman key exchange.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:42
DhParameters params
Definition: dh.h:61
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:109
Mpi p
Prime modulus.
Definition: dh.h:50
General definitions for cryptographic algorithms.
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:195
uint8_t z
Definition: dns_common.h:175
#define TRACE_DEBUG(...)
Definition: debug.h:106
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:107
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
Mpi g
Generator.
Definition: dh.h:51
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:295
error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
Diffie-Hellman key pair generation.
Definition: dh.c:91
Mpi ya
One's own public value.
Definition: dh.h:63
Diffie-Hellman parameters.
Definition: dh.h:48
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
#define TRACE_DEBUG_MPI(p, a)
Definition: debug.h:109
int_t mpiCompInt(const Mpi *a, int_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:339
void dhInit(DhContext *context)
Initialize Diffie-Hellman context.
Definition: dh.c:54
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:156
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:62