1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Crypto Component */
17 /** */
18 /** Diffie-Hellman (DH) */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_CRYPTO_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "nx_crypto_dh.h"
29 #ifndef NX_CRYPTO_SELF_TEST
30
31 /* The Diffie-Hellman group 2 modulus. */
32 /* Modulus, in byte stream, be */
33 /* ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff */
34 static const HN_UBASE _nx_dh_group_2_modulus[] =
35 {
36 HN_ULONG_TO_UBASE(0xFFFFFFFF), HN_ULONG_TO_UBASE(0xFFFFFFFF),
37 HN_ULONG_TO_UBASE(0xECE65381), HN_ULONG_TO_UBASE(0x49286651),
38 HN_ULONG_TO_UBASE(0x7C4B1FE6), HN_ULONG_TO_UBASE(0xAE9F2411),
39 HN_ULONG_TO_UBASE(0x5A899FA5), HN_ULONG_TO_UBASE(0xEE386BFB),
40 HN_ULONG_TO_UBASE(0xF406B7ED), HN_ULONG_TO_UBASE(0x0BFF5CB6),
41 HN_ULONG_TO_UBASE(0xA637ED6B), HN_ULONG_TO_UBASE(0xF44C42E9),
42 HN_ULONG_TO_UBASE(0x625E7EC6), HN_ULONG_TO_UBASE(0xE485B576),
43 HN_ULONG_TO_UBASE(0x6D51C245), HN_ULONG_TO_UBASE(0x4FE1356D),
44 HN_ULONG_TO_UBASE(0xF25F1437), HN_ULONG_TO_UBASE(0x302B0A6D),
45 HN_ULONG_TO_UBASE(0xCD3A431B), HN_ULONG_TO_UBASE(0xEF9519B3),
46 HN_ULONG_TO_UBASE(0x8E3404DD), HN_ULONG_TO_UBASE(0x514A0879),
47 HN_ULONG_TO_UBASE(0x3B139B22), HN_ULONG_TO_UBASE(0x020BBEA6),
48 HN_ULONG_TO_UBASE(0x8A67CC74), HN_ULONG_TO_UBASE(0x29024E08),
49 HN_ULONG_TO_UBASE(0x80DC1CD1), HN_ULONG_TO_UBASE(0xC4C6628B),
50 HN_ULONG_TO_UBASE(0x2168C234), HN_ULONG_TO_UBASE(0xC90FDAA2),
51 HN_ULONG_TO_UBASE(0xFFFFFFFF), HN_ULONG_TO_UBASE(0xFFFFFFFF)
52 };
53
54
55 /**************************************************************************/
56 /* */
57 /* FUNCTION RELEASE */
58 /* */
59 /* _nx_crypto_dh_setup PORTABLE C */
60 /* 6.1.7 */
61 /* AUTHOR */
62 /* */
63 /* Timothy Stapko, Microsoft Corporation */
64 /* */
65 /* DESCRIPTION */
66 /* */
67 /* This function sets up a Diffie-Hellman context by generating a */
68 /* local. */
69 /* */
70 /* Note: The scratch buffer must be able to hold a number of *bytes* */
71 /* at least equal to NX_CRYPTO_DIFFIE_HELLMAN_SCRATCH_SIZE. */
72 /* */
73 /* INPUT */
74 /* */
75 /* dh_ptr Diffie-Hellman context */
76 /* local_public_key Pointer to local public key */
77 /* local_public_key_len Local public key length */
78 /* dh_group_num Chosen DH group number */
79 /* scratch_buf_ptr Pointer to scratch buffer, */
80 /* which cannot be smaller */
81 /* than 6 times of the key */
82 /* size (in bytes). This */
83 /* scratch buffer can be */
84 /* reused after this function */
85 /* returns. */
86 /* */
87 /* OUTPUT */
88 /* */
89 /* status Completion status */
90 /* */
91 /* CALLS */
92 /* */
93 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
94 /* number to remove leading */
95 /* zeroes */
96 /* _nx_crypto_huge_number_mont_power_modulus */
97 /* Raise a huge number for */
98 /* montgomery reduction */
99 /* */
100 /* CALLED BY */
101 /* */
102 /* Application Code */
103 /* */
104 /* RELEASE HISTORY */
105 /* */
106 /* DATE NAME DESCRIPTION */
107 /* */
108 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
109 /* 09-30-2020 Timothy Stapko Modified comment(s), */
110 /* resulting in version 6.1 */
111 /* 06-02-2021 Bhupendra Naphade Modified comment(s), */
112 /* renamed FIPS symbol to */
113 /* self-test, */
114 /* resulting in version 6.1.7 */
115 /* */
116 /**************************************************************************/
_nx_crypto_dh_setup(NX_CRYPTO_DH * dh_ptr,UCHAR * local_public_key_ptr,UINT * local_public_key_len_ptr,ULONG dh_group_num,HN_UBASE * scratch_buf_ptr)117 NX_CRYPTO_KEEP UINT _nx_crypto_dh_setup(NX_CRYPTO_DH *dh_ptr,
118 UCHAR *local_public_key_ptr,
119 UINT *local_public_key_len_ptr,
120 ULONG dh_group_num,
121 HN_UBASE *scratch_buf_ptr)
122 {
123
124 UINT i;
125
126
127 /* Actual huge numbers used in calculations */
128 NX_CRYPTO_HUGE_NUMBER modulus, public_key, private_key, generator;
129 HN_UBASE generator_value;
130
131 NX_CRYPTO_STATE_CHECK
132
133 /* Assign the desired key size based on the chosen Diffie-Hellman group. */
134 switch (dh_group_num)
135 {
136 case NX_CRYPTO_DH_GROUP_2:
137 dh_ptr -> nx_crypto_dh_key_size = NX_CRYPTO_DIFFIE_HELLMAN_GROUP_2_KEY_SIZE;
138 dh_ptr -> nx_crypto_dh_modulus = (HN_UBASE *)_nx_dh_group_2_modulus;
139
140 NX_CRYPTO_HUGE_NUMBER_INITIALIZE_DIGIT(&generator, &generator_value,
141 NX_CRYPTO_DH_GROUP_2_GENERATOR)
142
143 /* Setup the modulus value. */
144 modulus.nx_crypto_huge_number_data = dh_ptr -> nx_crypto_dh_modulus;
145 modulus.nx_crypto_huge_number_size = dh_ptr -> nx_crypto_dh_key_size >> HN_SIZE_SHIFT;
146 modulus.nx_crypto_huge_buffer_size = dh_ptr -> nx_crypto_dh_key_size;
147 modulus.nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
148
149
150 break;
151
152 default:
153 /* No supported group specified - error! */
154 return(NX_CRYPTO_NOT_SUCCESSFUL);
155 }
156
157 /* Local pointer for pointer arithmetic. The power-modulus operation does not require the scratch area
158 to be "clean". Therefore no need to zero out the buffer.
159
160 Public key buffer (and scratch). */
161 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&public_key, scratch_buf_ptr, dh_ptr -> nx_crypto_dh_key_size << 1);
162
163 /* Private key buffer - note that no scratch is required for the private key. */
164 private_key.nx_crypto_huge_number_data = dh_ptr -> nx_crypto_dh_private_key_buffer;
165 private_key.nx_crypto_huge_number_size = dh_ptr -> nx_crypto_dh_key_size >> HN_SIZE_SHIFT;
166 private_key.nx_crypto_huge_buffer_size = sizeof(dh_ptr -> nx_crypto_dh_private_key_buffer);
167 private_key.nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
168
169
170 /* Generate the private key. */
171 for (i = 0; i < private_key.nx_crypto_huge_number_size; i++)
172 {
173 /* Grab a random value - this may be more than one byte and we want to use
174 all the bytes in the value, so we do not simply copy the random_value
175 into the buffers. */
176 dh_ptr -> nx_crypto_dh_private_key_buffer[i] = (HN_UBASE)((HN_UBASE)(NX_CRYPTO_RAND()) & HN_MASK);
177 }
178
179 /* Finally, generate the public key from the private key, modulus, and the generator.
180 The actual calculation is "public_key = (generator**private_key) % modulus"
181 where the "**" denotes exponentiation. */
182 _nx_crypto_huge_number_mont_power_modulus(&generator, &private_key,
183 &modulus, &public_key, scratch_buf_ptr);
184
185 /* Copy the public key into the return buffer. */
186 _nx_crypto_huge_number_extract(&public_key, local_public_key_ptr,
187 dh_ptr -> nx_crypto_dh_key_size, local_public_key_len_ptr);
188
189 return(NX_CRYPTO_SUCCESS);
190 }
191
192
193 /**************************************************************************/
194 /* */
195 /* FUNCTION RELEASE */
196 /* */
197 /* _nx_crypto_dh_compute_secret PORTABLE C */
198 /* 6.1 */
199 /* AUTHOR */
200 /* */
201 /* Timothy Stapko, Microsoft Corporation */
202 /* */
203 /* DESCRIPTION */
204 /* */
205 /* This function computes the Diffie-Hellman shared secret using an */
206 /* existing Diffie-Hellman context and a public key received from a */
207 /* remote entity, usually as part of an IPSEC or SSL key exchange. */
208 /* */
209 /* Note: The scratch buffer must be able to hold a number of *bytes* */
210 /* at least equal to NX_CRYPTO_DIFFIE_HELLMAN_SCRATCH_SIZE. */
211 /* */
212 /* INPUT */
213 /* */
214 /* dh_ptr Diffie-Hellman context */
215 /* share_secret_key_ptr Shared secret buffer pointer */
216 /* share_secret_key_len_ptr Length of shared secret */
217 /* remote_public_key Pointer to remote public key */
218 /* remote_public_key_len Remote public key length */
219 /* scratch_buf_ptr Pointer to scratch buffer, */
220 /* which cannot be smaller */
221 /* than 8 times of the key */
222 /* size (in bytes). This */
223 /* scratch buffer can be */
224 /* reused after this function */
225 /* returns. */
226 /* */
227 /* OUTPUT */
228 /* */
229 /* status Completion status */
230 /* */
231 /* CALLS */
232 /* */
233 /* _nx_crypto_huge_number_extract Extract huge number */
234 /* _nx_crypto_huge_number_setup Setup huge number */
235 /* _nx_crypto_huge_number_mont_power_modulus */
236 /* Raise a huge number for */
237 /* montgomery reduction */
238 /* */
239 /* CALLED BY */
240 /* */
241 /* Application Code */
242 /* */
243 /* RELEASE HISTORY */
244 /* */
245 /* DATE NAME DESCRIPTION */
246 /* */
247 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
248 /* 09-30-2020 Timothy Stapko Modified comment(s), */
249 /* resulting in version 6.1 */
250 /* */
251 /**************************************************************************/
_nx_crypto_dh_compute_secret(NX_CRYPTO_DH * dh_ptr,UCHAR * share_secret_key_ptr,ULONG * share_secret_key_len_ptr,UCHAR * remote_public_key,ULONG remote_public_key_len,HN_UBASE * scratch_buf_ptr)252 NX_CRYPTO_KEEP UINT _nx_crypto_dh_compute_secret(NX_CRYPTO_DH *dh_ptr,
253 UCHAR *share_secret_key_ptr,
254 ULONG *share_secret_key_len_ptr,
255 UCHAR *remote_public_key,
256 ULONG remote_public_key_len,
257 HN_UBASE *scratch_buf_ptr)
258 {
259
260 UINT key_size;
261
262 /* Actual huge numbers used in calculations */
263 NX_CRYPTO_HUGE_NUMBER modulus, public_key, private_key, shared_secret;
264
265 NX_CRYPTO_STATE_CHECK
266
267 /* Make sure the key size was assigned before we do anything else. Generally, this means
268 _nx_crypto_dh_setup was not called to set up the NX_DH structure prior to this call. */
269 if (0 == dh_ptr -> nx_crypto_dh_key_size)
270 {
271 return(NX_CRYPTO_NOT_SUCCESSFUL);
272 }
273
274 /* Make sure the remote public key is small enough to fit into the huge number buffer. */
275 if (remote_public_key_len > dh_ptr -> nx_crypto_dh_key_size)
276 {
277 return(NX_CRYPTO_NOT_SUCCESSFUL);
278 }
279
280 /* Figure out the sizes of our keys and buffers. We need 2X the key size for our buffer space. */
281 key_size = dh_ptr -> nx_crypto_dh_key_size;
282
283 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&public_key, scratch_buf_ptr, key_size);
284 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&shared_secret, scratch_buf_ptr, key_size << 1);
285
286 /* Copy the remote public key from the caller's buffer. */
287 _nx_crypto_huge_number_setup(&public_key, remote_public_key, remote_public_key_len);
288
289
290
291 /* Set up each of the buffers - point into the scratch buffer at increments of the DH buffer size. */
292 modulus.nx_crypto_huge_number_data = (HN_UBASE *)dh_ptr -> nx_crypto_dh_modulus;
293 modulus.nx_crypto_huge_number_size = key_size >> HN_SIZE_SHIFT;
294 modulus.nx_crypto_huge_buffer_size = key_size;
295 modulus.nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
296
297
298 /* Private key buffer - note that no scratch is required for the private key, but we set it in case
299 it is needed in the future. */
300 private_key.nx_crypto_huge_number_data = (HN_UBASE *)dh_ptr -> nx_crypto_dh_private_key_buffer;
301 private_key.nx_crypto_huge_number_size = key_size >> HN_SIZE_SHIFT;
302 private_key.nx_crypto_huge_buffer_size = key_size;
303 private_key.nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
304
305 /* Finally, generate shared secret from the remote public key, our generated private key, and the modulus, modulus.
306 The actual calculation is "shared_secret = (public_key**private_key) % modulus"
307 where the "**" denotes exponentiation. */
308 _nx_crypto_huge_number_mont_power_modulus(&public_key, &private_key, &modulus,
309 &shared_secret, scratch_buf_ptr);
310
311 /* Now we have a shared secret to return to the caller. Check to make sure the buffer is large enough to hold the public key. */
312 if (*share_secret_key_len_ptr < key_size)
313 {
314 return(NX_CRYPTO_NOT_SUCCESSFUL);
315 }
316
317 /* The public key size is simply the key size for this group. */
318
319 /* Copy the shared secret into the return buffer. */
320 _nx_crypto_huge_number_extract(&shared_secret, share_secret_key_ptr,
321 key_size, (UINT *)share_secret_key_len_ptr);
322
323 return(NX_CRYPTO_SUCCESS);
324 }
325
326 #endif
327