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