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 /** RSA public-key encryption algorithm */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #include "nx_crypto_rsa.h"
24 #include "nx_crypto_huge_number.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_crypto_rsa_operation PORTABLE C */
31 /* 6.1 */
32 /* AUTHOR */
33 /* */
34 /* Timothy Stapko, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function performs an RSA encryption/decryption operation - */
39 /* for RSA the operation is the same but with different values */
40 /* for the exponent. */
41 /* */
42 /* The output is always the same length as the modulus. */
43 /* */
44 /* If NULL is passed for the scratch buffer pointer, an internal */
45 /* scratch buffer is used. */
46 /* */
47 /* INPUT */
48 /* */
49 /* exponent RSA exponent */
50 /* exponent_length Length of exponent in bytes */
51 /* modulus RSA modulus */
52 /* modulus_length Length of modulus in bytes */
53 /* p RSA prime p */
54 /* p_length Length of p in bytes */
55 /* q RSA prime q */
56 /* q_length Length of q in bytes */
57 /* input Input data */
58 /* input_length Length of input in bytes */
59 /* output Output buffer */
60 /* scratch_buf_ptr Pointer to scratch buffer */
61 /* scratch_buf_length Length of scratch buffer */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* status Completion status */
66 /* */
67 /* CALLS */
68 /* */
69 /* _nx_crypto_huge_number_setup Setup huge number */
70 /* _nx_crypto_huge_number_crt_power_modulus */
71 /* Raise a huge number for CRT */
72 /* _nx_crypto_huge_number_mont_power_modulus */
73 /* Raise a huge number for */
74 /* montgomery reduction */
75 /* _nx_crypto_huge_number_extract Extract huge number */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* _nx_crypto_method_rsa_operation Handle RSA operation */
80 /* */
81 /* RELEASE HISTORY */
82 /* */
83 /* DATE NAME DESCRIPTION */
84 /* */
85 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
86 /* 09-30-2020 Timothy Stapko Modified comment(s), */
87 /* resulting in version 6.1 */
88 /* 03-08-2023 Yanwu Cai Modified comment(s), aligned */
89 /* buffer size of huge number, */
90 /* resulting in version 6.2.1 */
91 /* */
92 /**************************************************************************/
_nx_crypto_rsa_operation(const UCHAR * exponent,UINT exponent_length,const UCHAR * modulus,UINT modulus_length,const UCHAR * p,UINT p_length,UCHAR * q,UINT q_length,const UCHAR * input,UINT input_length,UCHAR * output,USHORT * scratch_buf_ptr,UINT scratch_buf_length)93 NX_CRYPTO_KEEP UINT _nx_crypto_rsa_operation(const UCHAR *exponent, UINT exponent_length, const UCHAR *modulus, UINT modulus_length,
94 const UCHAR *p, UINT p_length, UCHAR *q, UINT q_length,
95 const UCHAR *input, UINT input_length, UCHAR *output,
96 USHORT *scratch_buf_ptr, UINT scratch_buf_length)
97 {
98 HN_UBASE *scratch;
99 UINT mod_length;
100 NX_CRYPTO_HUGE_NUMBER modulus_hn, exponent_hn, input_hn, output_hn, p_hn, q_hn;
101
102 NX_CRYPTO_PARAMETER_NOT_USED(scratch_buf_length);
103
104 /* The RSA operation is reversible so both encryption and decryption can be done with the same operation. */
105 /* Local pointer for pointer arithmetic. */
106 scratch = (HN_UBASE *)scratch_buf_ptr;
107
108 /* Set up each of the buffers - point into the scratch buffer at increments of the DH buffer size. */
109 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&modulus_hn, scratch, modulus_length);
110
111 /* Input buffer(and scratch). */
112 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&input_hn, scratch, modulus_length);
113
114 /* Exponent buffer (and scratch). */
115 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&exponent_hn, scratch, modulus_length);
116
117 /* Output buffer (and scratch). */
118 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&output_hn, scratch, modulus_length << 1);
119
120 /* Copy the exponent from the caller's buffer. */
121 _nx_crypto_huge_number_setup(&exponent_hn, exponent, exponent_length);
122
123 /* Copy the input from the caller's buffer. */
124 _nx_crypto_huge_number_setup(&input_hn, input, input_length);
125
126 /* Copy the modulus from the caller's buffer. */
127 _nx_crypto_huge_number_setup(&modulus_hn, modulus, modulus_length);
128
129 if (p && q)
130 {
131
132 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&p_hn, scratch, modulus_length >> 1);
133
134 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&q_hn, scratch, modulus_length >> 1);
135
136 /* Copy the prime p and q from the caller's buffer. */
137 _nx_crypto_huge_number_setup(&p_hn, p, p_length);
138 _nx_crypto_huge_number_setup(&q_hn, q, q_length);
139
140 /* Finally, generate shared secret from the remote public key, our generated private key, and the modulus, modulus.
141 The actual calculation is "shared_secret = (public_key**private_key) % modulus"
142 where the "**" denotes exponentiation. */
143 _nx_crypto_huge_number_crt_power_modulus(&input_hn, &exponent_hn, &p_hn, &q_hn,
144 &modulus_hn, &output_hn,
145 scratch);
146 }
147 else
148 {
149
150 /* Finally, generate shared secret from the remote public key, our generated private key, and the modulus, modulus.
151 The actual calculation is "shared_secret = (public_key**private_key) % modulus"
152 where the "**" denotes exponentiation. */
153 _nx_crypto_huge_number_mont_power_modulus(&input_hn, &exponent_hn, &modulus_hn,
154 &output_hn, scratch);
155 }
156
157 /* Copy the shared secret into the return buffer. */
158 _nx_crypto_huge_number_extract(&output_hn, output, modulus_length, &mod_length);
159
160 return(NX_CRYPTO_SUCCESS);
161 }
162
163 /**************************************************************************/
164 /* */
165 /* FUNCTION RELEASE */
166 /* */
167 /* _nx_crypto_method_rsa_init PORTABLE C */
168 /* 6.3.0 */
169 /* AUTHOR */
170 /* */
171 /* Timothy Stapko, Microsoft Corporation */
172 /* */
173 /* DESCRIPTION */
174 /* */
175 /* This function initializes the modulus for RSA context. */
176 /* */
177 /* INPUT */
178 /* */
179 /* method Pointer to RSA crypto method */
180 /* key Pointer to modulus */
181 /* key_size_in_bits Length of modulus in bits */
182 /* handle Handle of method */
183 /* crypto_metadata Pointer to RSA context */
184 /* crypto_metadata_size Size of RSA context */
185 /* */
186 /* OUTPUT */
187 /* */
188 /* status Completion status */
189 /* */
190 /* CALLS */
191 /* */
192 /* None */
193 /* */
194 /* CALLED BY */
195 /* */
196 /* Application Code */
197 /* */
198 /* RELEASE HISTORY */
199 /* */
200 /* DATE NAME DESCRIPTION */
201 /* */
202 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
203 /* 09-30-2020 Timothy Stapko Modified comment(s), */
204 /* resulting in version 6.1 */
205 /* 10-31-2023 Yanwu Cai Modified comment(s), */
206 /* resulting in version 6.3.0 */
207 /* */
208 /**************************************************************************/
_nx_crypto_method_rsa_init(struct NX_CRYPTO_METHOD_STRUCT * method,UCHAR * key,NX_CRYPTO_KEY_SIZE key_size_in_bits,VOID ** handle,VOID * crypto_metadata,ULONG crypto_metadata_size)209 NX_CRYPTO_KEEP UINT _nx_crypto_method_rsa_init(struct NX_CRYPTO_METHOD_STRUCT *method,
210 UCHAR *key, NX_CRYPTO_KEY_SIZE key_size_in_bits,
211 VOID **handle,
212 VOID *crypto_metadata,
213 ULONG crypto_metadata_size)
214 {
215 NX_CRYPTO_RSA *ctx;
216
217 NX_CRYPTO_PARAMETER_NOT_USED(handle);
218
219 NX_CRYPTO_STATE_CHECK
220
221 if ((method == NX_CRYPTO_NULL) || (key == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL))
222 {
223 return(NX_CRYPTO_PTR_ERROR);
224 }
225
226 /* Verify the metadata address is 4-byte aligned. */
227 if((((ULONG)crypto_metadata) & 0x3) != 0)
228 {
229 return(NX_CRYPTO_PTR_ERROR);
230 }
231
232 if(crypto_metadata_size < sizeof(NX_CRYPTO_RSA))
233 {
234 return(NX_CRYPTO_PTR_ERROR);
235 }
236
237 ctx = (NX_CRYPTO_RSA *)crypto_metadata;
238
239 ctx -> nx_crypto_rsa_modulus = key;
240 ctx -> nx_crypto_rsa_modulus_length = key_size_in_bits >> 3;
241 ctx -> nx_crypto_rsa_prime_p = NX_CRYPTO_NULL;
242 ctx -> nx_crypto_rsa_prime_p_length = 0;
243 ctx -> nx_crypto_rsa_prime_q = NX_CRYPTO_NULL;
244 ctx -> nx_crypto_rsa_prime_q_length = 0;
245
246 /* Call _nx_crypto_crypto_rsa_set_prime() to set p and q for private key.
247 * Chinese Remainder Theorem will be used when p and q are set. */
248
249 return(NX_CRYPTO_SUCCESS);
250 }
251
252
253 /**************************************************************************/
254 /* */
255 /* FUNCTION RELEASE */
256 /* */
257 /* _nx_crypto_method_rsa_cleanup PORTABLE C */
258 /* 6.1 */
259 /* AUTHOR */
260 /* */
261 /* Timothy Stapko, Microsoft Corporation */
262 /* */
263 /* DESCRIPTION */
264 /* */
265 /* This function cleans up the crypto metadata. */
266 /* */
267 /* INPUT */
268 /* */
269 /* crypto_metadata Crypto metadata */
270 /* */
271 /* OUTPUT */
272 /* */
273 /* status Completion status */
274 /* */
275 /* CALLS */
276 /* */
277 /* NX_CRYPTO_MEMSET Set the memory */
278 /* */
279 /* CALLED BY */
280 /* */
281 /* Application Code */
282 /* */
283 /* RELEASE HISTORY */
284 /* */
285 /* DATE NAME DESCRIPTION */
286 /* */
287 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
288 /* 09-30-2020 Timothy Stapko Modified comment(s), */
289 /* resulting in version 6.1 */
290 /* */
291 /**************************************************************************/
_nx_crypto_method_rsa_cleanup(VOID * crypto_metadata)292 NX_CRYPTO_KEEP UINT _nx_crypto_method_rsa_cleanup(VOID *crypto_metadata)
293 {
294
295 NX_CRYPTO_STATE_CHECK
296
297 #ifdef NX_SECURE_KEY_CLEAR
298 if (!crypto_metadata)
299 return (NX_CRYPTO_SUCCESS);
300
301 /* Clean up the crypto metadata. */
302 NX_CRYPTO_MEMSET(crypto_metadata, 0, sizeof(NX_CRYPTO_RSA));
303 #else
304 NX_CRYPTO_PARAMETER_NOT_USED(crypto_metadata);
305 #endif/* NX_SECURE_KEY_CLEAR */
306
307 return(NX_CRYPTO_SUCCESS);
308 }
309
310
311 /**************************************************************************/
312 /* */
313 /* FUNCTION RELEASE */
314 /* */
315 /* _nx_crypto_method_rsa_operation PORTABLE C */
316 /* 6.3.0 */
317 /* AUTHOR */
318 /* */
319 /* Timothy Stapko, Microsoft Corporation */
320 /* */
321 /* DESCRIPTION */
322 /* */
323 /* This function is the RSA operation function for crypto method. */
324 /* */
325 /* INPUT */
326 /* */
327 /* op Operation */
328 /* handle Handle to method */
329 /* method Pointer to RSA crypto method */
330 /* key Exponent of RSA operation */
331 /* key_size_in_bits Size of exponent in bits */
332 /* input Input stream */
333 /* input_length_in_byte Length of input in byte */
334 /* iv_ptr Initial Vector (not used) */
335 /* output Output stream */
336 /* output_length_in_byte Length of output in byte */
337 /* crypto_metadata Pointer to RSA context */
338 /* crypto_metadata_size Size of RSA context */
339 /* packet_ptr Pointer to packet (not used) */
340 /* nx_crypto_hw_process_callback Pointer to callback function */
341 /* (not used) */
342 /* */
343 /* OUTPUT */
344 /* */
345 /* status Completion status */
346 /* */
347 /* CALLS */
348 /* */
349 /* _nx_crypto_rsa_operation Perform RSA operation */
350 /* */
351 /* CALLED BY */
352 /* */
353 /* Application Code */
354 /* */
355 /* RELEASE HISTORY */
356 /* */
357 /* DATE NAME DESCRIPTION */
358 /* */
359 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
360 /* 09-30-2020 Timothy Stapko Modified comment(s), */
361 /* resulting in version 6.1 */
362 /* 10-31-2023 Yanwu Cai Modified comment(s), */
363 /* resulting in version 6.3.0 */
364 /* */
365 /**************************************************************************/
_nx_crypto_method_rsa_operation(UINT op,VOID * handle,struct NX_CRYPTO_METHOD_STRUCT * method,UCHAR * key,NX_CRYPTO_KEY_SIZE key_size_in_bits,UCHAR * input,ULONG input_length_in_byte,UCHAR * iv_ptr,UCHAR * output,ULONG output_length_in_byte,VOID * crypto_metadata,ULONG crypto_metadata_size,VOID * packet_ptr,VOID (* nx_crypto_hw_process_callback)(VOID * packet_ptr,UINT status))366 NX_CRYPTO_KEEP UINT _nx_crypto_method_rsa_operation(UINT op, /* Encrypt, Decrypt, Authenticate */
367 VOID *handle, /* Crypto handler */
368 struct NX_CRYPTO_METHOD_STRUCT *method,
369 UCHAR *key,
370 NX_CRYPTO_KEY_SIZE key_size_in_bits,
371 UCHAR *input,
372 ULONG input_length_in_byte,
373 UCHAR *iv_ptr,
374 UCHAR *output,
375 ULONG output_length_in_byte,
376 VOID *crypto_metadata,
377 ULONG crypto_metadata_size,
378 VOID *packet_ptr,
379 VOID (*nx_crypto_hw_process_callback)(VOID *packet_ptr, UINT status))
380 {
381 NX_CRYPTO_RSA *ctx;
382 UINT return_value = NX_CRYPTO_SUCCESS;
383
384
385 NX_CRYPTO_PARAMETER_NOT_USED(handle);
386 NX_CRYPTO_PARAMETER_NOT_USED(iv_ptr);
387 NX_CRYPTO_PARAMETER_NOT_USED(packet_ptr);
388 NX_CRYPTO_PARAMETER_NOT_USED(nx_crypto_hw_process_callback);
389
390 NX_CRYPTO_STATE_CHECK
391
392 /* Verify the metadata address is 4-byte aligned. */
393 if((method == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL) || ((((ULONG)crypto_metadata) & 0x3) != 0))
394 {
395 return(NX_CRYPTO_PTR_ERROR);
396 }
397
398 if(crypto_metadata_size < sizeof(NX_CRYPTO_RSA))
399 {
400 return(NX_CRYPTO_PTR_ERROR);
401 }
402
403 ctx = (NX_CRYPTO_RSA *)crypto_metadata;
404
405
406 if (op == NX_CRYPTO_SET_PRIME_P)
407 {
408 ctx -> nx_crypto_rsa_prime_p = input;
409 ctx -> nx_crypto_rsa_prime_p_length = input_length_in_byte;
410 }
411 else if (op == NX_CRYPTO_SET_PRIME_Q)
412 {
413 ctx -> nx_crypto_rsa_prime_q = input;
414 ctx -> nx_crypto_rsa_prime_q_length = input_length_in_byte;
415 }
416 else
417 {
418
419 if (key == NX_CRYPTO_NULL)
420 {
421 return(NX_CRYPTO_PTR_ERROR);
422 }
423
424 if(output_length_in_byte < (key_size_in_bits >> 3))
425 return(NX_CRYPTO_INVALID_BUFFER_SIZE);
426
427 if (input_length_in_byte > (ctx -> nx_crypto_rsa_modulus_length))
428 {
429 return(NX_CRYPTO_PTR_ERROR);
430 }
431
432 return_value = _nx_crypto_rsa_operation(key,
433 key_size_in_bits >> 3,
434 ctx -> nx_crypto_rsa_modulus,
435 ctx -> nx_crypto_rsa_modulus_length,
436 ctx -> nx_crypto_rsa_prime_p,
437 ctx -> nx_crypto_rsa_prime_p_length,
438 ctx -> nx_crypto_rsa_prime_q,
439 ctx -> nx_crypto_rsa_prime_q_length,
440 input, input_length_in_byte,
441 output,
442 ctx -> nx_crypto_rsa_scratch_buffer,
443 NX_CRYPTO_RSA_SCRATCH_BUFFER_SIZE);
444 }
445
446 return(return_value);
447 }
448
449