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