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 /** HMAC-based Extract-and-Expand Key Derivation Function (HKDF) */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #include "nx_crypto_hkdf.h"
24 #include "nx_crypto_hmac.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_crypto_method_hkdf_init PORTABLE C */
31 /* 6.3.0 */
32 /* AUTHOR */
33 /* */
34 /* Timothy Stapko, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function is the common crypto method initialization routine */
39 /* for the Microsoft implementation of the HKDF cryptographic */
40 /* algorithm. */
41 /* */
42 /* INPUT */
43 /* */
44 /* method Pointer to crypto method */
45 /* key Pointer to key */
46 /* key_size_in_bits Length of key size in bits */
47 /* handler Returned crypto handler */
48 /* crypto_metadata Metadata area */
49 /* crypto_metadata_size Size of the metadata area */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* status Completion status */
54 /* */
55 /* CALLS */
56 /* */
57 /* None */
58 /* */
59 /* CALLED BY */
60 /* */
61 /* Application Code */
62 /* */
63 /* RELEASE HISTORY */
64 /* */
65 /* DATE NAME DESCRIPTION */
66 /* */
67 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
68 /* 09-30-2020 Timothy Stapko Modified comment(s), */
69 /* resulting in version 6.1 */
70 /* 10-31-2023 Yanwu Cai Modified comment(s), */
71 /* resulting in version 6.3.0 */
72 /* */
73 /**************************************************************************/
_nx_crypto_method_hkdf_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)74 NX_CRYPTO_KEEP UINT _nx_crypto_method_hkdf_init(struct NX_CRYPTO_METHOD_STRUCT *method,
75 UCHAR *key, NX_CRYPTO_KEY_SIZE key_size_in_bits,
76 VOID **handle,
77 VOID *crypto_metadata,
78 ULONG crypto_metadata_size)
79 {
80 NX_CRYPTO_HKDF *hkdf;
81
82 NX_CRYPTO_PARAMETER_NOT_USED(handle);
83
84 NX_CRYPTO_STATE_CHECK
85
86 /* We don't need a key in the HKDF init. */
87 if ((method == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL))
88 {
89 return(NX_CRYPTO_POINTER_ERROR);
90 }
91
92 /* Verify the metadata address is 4-byte aligned. */
93 if((((ULONG)crypto_metadata) & 0x3) != 0)
94 {
95 return(NX_CRYPTO_METADATA_UNALIGNED);
96 }
97
98 if(crypto_metadata_size < sizeof(NX_CRYPTO_HKDF))
99 {
100 return(NX_CRYPTO_INVALID_BUFFER_SIZE);
101 }
102
103 hkdf = (NX_CRYPTO_HKDF *)crypto_metadata;
104
105 /* Initialize IKM with key data. */
106 hkdf->nx_crypto_hkdf_ikm = key;
107 hkdf->nx_crypto_hkdf_ikm_length = (key_size_in_bits << 3);
108
109 /* Initialize HMAC and HASH methods. */
110 hkdf->nx_crypto_hmac_method = NX_CRYPTO_NULL;
111 hkdf->nx_crypto_hash_method = NX_CRYPTO_NULL;
112
113 return(NX_CRYPTO_SUCCESS);
114 }
115
116
117 /**************************************************************************/
118 /* */
119 /* FUNCTION RELEASE */
120 /* */
121 /* _nx_crypto_method_hkdf_cleanup PORTABLE C */
122 /* 6.1 */
123 /* AUTHOR */
124 /* */
125 /* Timothy Stapko, Microsoft Corporation */
126 /* */
127 /* DESCRIPTION */
128 /* */
129 /* This function cleans up the crypto metadata for the HKDF operation. */
130 /* */
131 /* INPUT */
132 /* */
133 /* crypto_metadata Crypto metadata */
134 /* */
135 /* OUTPUT */
136 /* */
137 /* status Completion status */
138 /* */
139 /* CALLS */
140 /* */
141 /* NX_CRYPTO_MEMSET Set the memory */
142 /* */
143 /* CALLED BY */
144 /* */
145 /* Application Code */
146 /* */
147 /* RELEASE HISTORY */
148 /* */
149 /* DATE NAME DESCRIPTION */
150 /* */
151 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
152 /* 09-30-2020 Timothy Stapko Modified comment(s), */
153 /* resulting in version 6.1 */
154 /* */
155 /**************************************************************************/
_nx_crypto_method_hkdf_cleanup(VOID * crypto_metadata)156 NX_CRYPTO_KEEP UINT _nx_crypto_method_hkdf_cleanup(VOID *crypto_metadata)
157 {
158 #ifdef NX_SECURE_KEY_CLEAR
159 NX_CRYPTO_METHOD *hmac_method;
160 NX_CRYPTO_HKDF *hkdf;
161 UINT status;
162 #endif
163 NX_CRYPTO_STATE_CHECK
164
165 #ifdef NX_SECURE_KEY_CLEAR
166 if (!crypto_metadata)
167 return (NX_CRYPTO_SUCCESS);
168
169 /* Clear the HMAC state. */
170 hkdf = (NX_CRYPTO_HKDF *)crypto_metadata;
171 hmac_method = hkdf->nx_crypto_hmac_method;
172
173 if(hmac_method)
174 {
175 status = hmac_method -> nx_crypto_cleanup(hmac_method);
176
177 if (status != NX_CRYPTO_SUCCESS)
178 {
179 return(status);
180 }
181 }
182
183 /* Clean up the HKDF metadata. */
184 NX_CRYPTO_MEMSET(crypto_metadata, 0, sizeof(NX_CRYPTO_HKDF));
185 #else
186 NX_CRYPTO_PARAMETER_NOT_USED(crypto_metadata);
187 #endif/* NX_SECURE_KEY_CLEAR */
188
189 return(NX_CRYPTO_SUCCESS);
190 }
191
192
193 /**************************************************************************/
194 /* */
195 /* FUNCTION RELEASE */
196 /* */
197 /* _nx_crypto_method_hkdf_operation PORTABLE C */
198 /* 6.3.0 */
199 /* AUTHOR */
200 /* */
201 /* Timothy Stapko, Microsoft Corporation */
202 /* */
203 /* DESCRIPTION */
204 /* */
205 /* This function provides the generic NetX Crypto API for the HKDF */
206 /* operation. */
207 /* */
208 /* INPUT */
209 /* */
210 /* op Operation Type */
211 /* Encrypt, Decrypt, Authenticate*/
212 /* handler Pointer to crypto context */
213 /* key Pointer to key */
214 /* key_size_in_bits Length of key size in bits */
215 /* input Input Stream */
216 /* input_length_in_byte Input Stream Length */
217 /* iv_ptr Initialized Vector */
218 /* output Output Stream */
219 /* output_length_in_byte Output Stream Length */
220 /* crypto_metadata Metadata area */
221 /* crypto_metadata_size Size of the metadata area */
222 /* packet_ptr Pointer to packet */
223 /* nx_crypto_hw_process_callback Callback function pointer */
224 /* */
225 /* OUTPUT */
226 /* */
227 /* status Completion status */
228 /* */
229 /* CALLS */
230 /* */
231 /* _nx_crypto_hkdf_extract Calculate the HKDF key */
232 /* _nx_crypto_hkdf_expand Generate HKDF key material */
233 /* */
234 /* CALLED BY */
235 /* */
236 /* Application Code */
237 /* */
238 /* RELEASE HISTORY */
239 /* */
240 /* DATE NAME DESCRIPTION */
241 /* */
242 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
243 /* 09-30-2020 Timothy Stapko Modified comment(s), improved */
244 /* buffer length verification, */
245 /* verified memcpy use cases, */
246 /* resulting in version 6.1 */
247 /* 10-31-2023 Yanwu Cai Modified comment(s), */
248 /* resulting in version 6.3.0 */
249 /* */
250 /**************************************************************************/
_nx_crypto_method_hkdf_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))251 NX_CRYPTO_KEEP UINT _nx_crypto_method_hkdf_operation(UINT op, /* Encrypt, Decrypt, Authenticate */
252 VOID *handle, /* Crypto handler */
253 struct NX_CRYPTO_METHOD_STRUCT *method,
254 UCHAR *key,
255 NX_CRYPTO_KEY_SIZE key_size_in_bits,
256 UCHAR *input,
257 ULONG input_length_in_byte,
258 UCHAR *iv_ptr,
259 UCHAR *output,
260 ULONG output_length_in_byte,
261 VOID *crypto_metadata,
262 ULONG crypto_metadata_size,
263 VOID *packet_ptr,
264 VOID (*nx_crypto_hw_process_callback)(VOID *packet_ptr, UINT status))
265 {
266 NX_CRYPTO_HKDF *hkdf;
267 UINT status;
268
269 NX_CRYPTO_PARAMETER_NOT_USED(handle);
270 NX_CRYPTO_PARAMETER_NOT_USED(iv_ptr);
271 NX_CRYPTO_PARAMETER_NOT_USED(packet_ptr);
272 NX_CRYPTO_PARAMETER_NOT_USED(nx_crypto_hw_process_callback);
273
274 NX_CRYPTO_STATE_CHECK
275
276 /* Verify the metadata address is 4-byte aligned. */
277 if((method == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL) || ((((ULONG)crypto_metadata) & 0x3) != 0))
278 {
279 return(NX_CRYPTO_POINTER_ERROR);
280 }
281
282 if(crypto_metadata_size < sizeof(NX_CRYPTO_HKDF))
283 {
284 return(NX_CRYPTO_INVALID_BUFFER_SIZE);
285 }
286
287 /* Get our control block for HKDF. */
288 hkdf = (NX_CRYPTO_HKDF *)(crypto_metadata);
289
290 status = NX_CRYPTO_SUCCESS;
291 switch (op)
292 {
293 case NX_CRYPTO_HKDF_SET_HMAC:
294 hkdf->nx_crypto_hmac_method = method;
295 if(hkdf->nx_crypto_hash_method != NX_CRYPTO_NULL)
296 {
297 /* Set the HMAC hash method. */
298 status = hkdf->nx_crypto_hmac_method->nx_crypto_operation(NX_CRYPTO_HMAC_SET_HASH, NX_CRYPTO_NULL,
299 hkdf->nx_crypto_hash_method, NX_CRYPTO_NULL, 0, NX_CRYPTO_NULL, 0,
300 NX_CRYPTO_NULL, NX_CRYPTO_NULL, 0, hkdf->nx_crypto_hmac_metadata,
301 sizeof(hkdf->nx_crypto_hmac_metadata), NX_CRYPTO_NULL, NX_CRYPTO_NULL);
302 }
303 break;
304 case NX_CRYPTO_HKDF_SET_HASH:
305 hkdf->nx_crypto_hash_method = method;
306 if(hkdf->nx_crypto_hmac_method != NX_CRYPTO_NULL)
307 {
308 /* Set the HMAC hash method. */
309 status = hkdf->nx_crypto_hmac_method->nx_crypto_operation(NX_CRYPTO_HMAC_SET_HASH, NX_CRYPTO_NULL,
310 method, NX_CRYPTO_NULL, 0, NX_CRYPTO_NULL, 0,
311 NX_CRYPTO_NULL, NX_CRYPTO_NULL, 0, hkdf->nx_crypto_hmac_metadata,
312 sizeof(hkdf->nx_crypto_hmac_metadata), NX_CRYPTO_NULL, NX_CRYPTO_NULL);
313 }
314 break;
315 case NX_CRYPTO_HKDF_SET_PRK:
316 if(key == NX_CRYPTO_NULL)
317 {
318 return(NX_CRYPTO_POINTER_ERROR);
319 }
320
321 if ((key_size_in_bits >> 3) > sizeof(hkdf->nx_crypto_hkdf_prk))
322 {
323 return(NX_CRYPTO_SIZE_ERROR);
324 }
325
326 /* Set the PRK and return. */
327 NX_CRYPTO_MEMCPY(hkdf->nx_crypto_hkdf_prk, key, (key_size_in_bits >> 3)); /* Use case of memcpy is verified. */
328 hkdf->nx_crypto_hkdf_prk_size = (key_size_in_bits >> 3);
329
330 break;
331 case NX_CRYPTO_HKDF_EXTRACT:
332 if(key == NX_CRYPTO_NULL)
333 {
334 return(NX_CRYPTO_POINTER_ERROR);
335 }
336
337 if(hkdf->nx_crypto_hash_method == NX_CRYPTO_NULL || hkdf->nx_crypto_hmac_method == NX_CRYPTO_NULL)
338 {
339 return(NX_CRYPTO_METHOD_INITIALIZATION_FAILURE);
340 }
341
342 /* Key is our "salt". The IKM should have been passed in the init function.*/
343 hkdf->nx_crypto_hkdf_salt = key;
344 hkdf->nx_crypto_hkdf_salt_length = (key_size_in_bits >> 3);
345
346 /* Initialize IKM with input data. */
347 hkdf->nx_crypto_hkdf_ikm = input;
348 hkdf->nx_crypto_hkdf_ikm_length = input_length_in_byte;
349
350 /* Our output size is the output size of the hash. */
351 hkdf->nx_crypto_hkdf_prk_size = hkdf->nx_crypto_hmac_method->nx_crypto_block_size_in_bytes;
352
353 status = _nx_crypto_hkdf_extract(hkdf);
354
355 if(status == NX_CRYPTO_SUCCESS)
356 {
357 if (output_length_in_byte < hkdf->nx_crypto_hkdf_prk_size)
358 {
359 return(NX_CRYPTO_SIZE_ERROR);
360 }
361
362 /* Copy the PRK into output. */
363 NX_CRYPTO_MEMCPY(output, hkdf->nx_crypto_hkdf_prk, hkdf->nx_crypto_hkdf_prk_size); /* Use case of memcpy is verified. */
364 }
365
366 break;
367
368 case NX_CRYPTO_HKDF_EXPAND:
369 if(key == NX_CRYPTO_NULL)
370 {
371 return(NX_CRYPTO_POINTER_ERROR);
372 }
373
374 if(hkdf->nx_crypto_hash_method == NX_CRYPTO_NULL || hkdf->nx_crypto_hmac_method == NX_CRYPTO_NULL)
375 {
376 return(NX_CRYPTO_METHOD_INITIALIZATION_FAILURE);
377 }
378
379 /* Key is our "info". The PRK should have been initialized by the call to NX_CRYPTO_HKDF_EXTRACT.*/
380 hkdf->nx_crypto_hkdf_info = key;
381 hkdf->nx_crypto_hkdf_info_size = (key_size_in_bits >> 3);
382
383 status = _nx_crypto_hkdf_expand(hkdf, output, output_length_in_byte);
384 break;
385 default:
386 break;
387 }
388
389 return(status);
390 }
391
392
393 /**************************************************************************/
394 /* */
395 /* FUNCTION RELEASE */
396 /* */
397 /* _nx_crypto_method_hkdf_extract PORTABLE C */
398 /* 6.1 */
399 /* AUTHOR */
400 /* */
401 /* Timothy Stapko, Microsoft Corporation */
402 /* */
403 /* DESCRIPTION */
404 /* */
405 /* This function performs the HKDF-extract operation detailed in RFC */
406 /* 5869. The output key is placed in the HKDF structure passed in. */
407 /* */
408 /* INPUT */
409 /* */
410 /* hkdf HKDF structure */
411 /* */
412 /* OUTPUT */
413 /* */
414 /* status Completion status */
415 /* */
416 /* CALLS */
417 /* */
418 /* [hash method] Perform selected HMAC hash */
419 /* */
420 /* CALLED BY */
421 /* */
422 /* Application Code */
423 /* */
424 /* RELEASE HISTORY */
425 /* */
426 /* DATE NAME DESCRIPTION */
427 /* */
428 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
429 /* 09-30-2020 Timothy Stapko Modified comment(s), */
430 /* resulting in version 6.1 */
431 /* */
432 /**************************************************************************/
_nx_crypto_hkdf_extract(NX_CRYPTO_HKDF * hkdf)433 UINT _nx_crypto_hkdf_extract(NX_CRYPTO_HKDF *hkdf)
434 {
435 UINT status;
436 UINT hash_size; /* the length of hmac output */
437 UCHAR *salt;
438 UINT salt_len;
439 UCHAR *ikm;
440 UINT ikm_len;
441 UCHAR *metadata;
442 UINT metadata_size;
443 UCHAR *hmac_output;
444 VOID *handler = NX_CRYPTO_NULL;
445 NX_CRYPTO_METHOD *hmac_method = hkdf -> nx_crypto_hmac_method;
446
447 NX_CRYPTO_STATE_CHECK
448
449 /* From RFC 5869:
450 * HKDF-Extract(salt, IKM) -> PRK
451 *
452 * Options:
453 * Hash a hash function; HashLen denotes the length of the
454 * hash function output in octets
455 *
456 * Inputs:
457 * salt optional salt value (a non-secret random value);
458 * if not provided, it is set to a string of HashLen zeros.
459 * IKM input keying material
460 *
461 * Output:
462 * PRK a pseudorandom key (of HashLen octets)
463 *
464 * The output PRK is calculated as follows:
465 *
466 * PRK = HMAC-Hash(salt, IKM)
467 *
468 */
469
470
471 /* Validate pointers. */
472 if (hmac_method == NX_CRYPTO_NULL
473 || hmac_method -> nx_crypto_operation == NX_CRYPTO_NULL
474 || hmac_method -> nx_crypto_cleanup == NX_CRYPTO_NULL
475 || hkdf->nx_crypto_hash_method == NX_CRYPTO_NULL)
476 {
477 return(NX_CRYPTO_INVALID_PARAMETER);
478 }
479
480 /* Initialize temporary variables. */
481 salt = hkdf->nx_crypto_hkdf_salt;
482 salt_len = hkdf->nx_crypto_hkdf_salt_length;
483 ikm = hkdf->nx_crypto_hkdf_ikm;
484 ikm_len = hkdf->nx_crypto_hkdf_ikm_length;
485 hash_size = hkdf -> nx_crypto_hash_method -> nx_crypto_ICV_size_in_bits >> 3;
486
487 metadata = hkdf->nx_crypto_hmac_metadata;
488 metadata_size = sizeof(hkdf->nx_crypto_hmac_metadata);
489 hmac_output = hkdf->nx_crypto_hkdf_prk;
490
491 /* Make sure we can store our output key. */
492 if (hash_size > sizeof(hkdf->nx_crypto_hkdf_prk))
493 {
494 return(NX_CRYPTO_INVALID_PARAMETER);
495 }
496
497 /* Assign the output size to our HKDF structure. */
498 hkdf->nx_crypto_hkdf_prk_size = hash_size;
499
500 /* Initialize hash method (check key sizes, etc.). */
501 if (hmac_method -> nx_crypto_init)
502 {
503 status = hmac_method -> nx_crypto_init(hmac_method,
504 salt,
505 (NX_CRYPTO_KEY_SIZE)(salt_len << 3),
506 &handler,
507 metadata,
508 metadata_size);
509
510 if(status != NX_CRYPTO_SUCCESS)
511 {
512 return(status);
513 }
514 }
515
516 /* Generate the output PRK. */
517 status = hmac_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
518 handler,
519 hmac_method,
520 salt,
521 (NX_CRYPTO_KEY_SIZE)(salt_len << 3),
522 ikm,
523 ikm_len,
524 NX_CRYPTO_NULL,
525 hmac_output,
526 hash_size,
527 metadata,
528 metadata_size,
529 NX_CRYPTO_NULL,
530 NX_CRYPTO_NULL);
531
532
533 return(status);
534 }
535
536 /**************************************************************************/
537 /* */
538 /* FUNCTION RELEASE */
539 /* */
540 /* _nx_crypto_method_hkdf_expand PORTABLE C */
541 /* 6.1 */
542 /* AUTHOR */
543 /* */
544 /* Timothy Stapko, Microsoft Corporation */
545 /* */
546 /* DESCRIPTION */
547 /* */
548 /* This function performs the HKDF-expand operation detailed in RFC */
549 /* 5869. The hdkf parameter contains the input key (PRK) and other */
550 /* parameters needed to generate the desired output data. */
551 /* */
552 /* INPUT */
553 /* */
554 /* hkdf HKDF structure */
555 /* */
556 /* OUTPUT */
557 /* */
558 /* status Completion status */
559 /* */
560 /* CALLS */
561 /* */
562 /* [hash method] Perform selected HMAC hash */
563 /* */
564 /* CALLED BY */
565 /* */
566 /* Application Code */
567 /* */
568 /* RELEASE HISTORY */
569 /* */
570 /* DATE NAME DESCRIPTION */
571 /* */
572 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
573 /* 09-30-2020 Timothy Stapko Modified comment(s), improved */
574 /* buffer length verification, */
575 /* verified memcpy use cases, */
576 /* resulting in version 6.1 */
577 /* */
578 /**************************************************************************/
_nx_crypto_hkdf_expand(NX_CRYPTO_HKDF * hkdf,UCHAR * output,UINT desired_length)579 UINT _nx_crypto_hkdf_expand(NX_CRYPTO_HKDF *hkdf, UCHAR *output, UINT desired_length)
580 {
581 UINT offset;
582 UINT N_count;
583 UINT hash_size; /* the length of hmac output */
584 UCHAR *prk;
585 UINT prk_len;
586 UCHAR *info;
587 UINT info_len;
588 UCHAR *metadata;
589 UINT metadata_size;
590 VOID *handler = NX_CRYPTO_NULL;
591 UINT output_len;
592 /* T(i) */
593 UCHAR *temp_T;
594 UINT temp_T_size, T_len, T_bytes_to_hash;
595 UINT i;
596 UINT status;
597
598 NX_CRYPTO_METHOD *hmac_method = hkdf -> nx_crypto_hmac_method;
599
600 NX_CRYPTO_STATE_CHECK
601
602 /* From RFC 5869:
603 * HKDF-Expand(PRK, info, L) -> OKM
604 *
605 * Options:
606 * Hash a hash function; HashLen denotes the length of the
607 * hash function output in octets
608 * Inputs:
609 * PRK a pseudorandom key of at least HashLen octets
610 * (usually, the output from the extract step)
611 * info optional context and application specific information
612 * (can be a zero-length string)
613 * L length of output keying material in octets
614 * (<= 255*HashLen)
615 *
616 * Output:
617 * OKM output keying material (of L octets)
618 *
619 * The output OKM is calculated as follows:
620 *
621 * N = ceil(L/HashLen)
622 * T = T(1) | T(2) | T(3) | ... | T(N)
623 * OKM = first L octets of T
624 *
625 * where:
626 * T(0) = empty string (zero length)
627 * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
628 * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
629 * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
630 * ...
631 *
632 * (where the constant concatenated to the end of each T(n) is a
633 * single octet.)
634 *
635 */
636
637
638 /* Validate pointers. */
639 if (hmac_method == NX_CRYPTO_NULL
640 || hmac_method -> nx_crypto_operation == NX_CRYPTO_NULL
641 || hmac_method -> nx_crypto_cleanup == NX_CRYPTO_NULL
642 || hkdf->nx_crypto_hash_method == NX_CRYPTO_NULL
643 || output == NX_CRYPTO_NULL)
644 {
645 return(NX_CRYPTO_INVALID_PARAMETER);
646 }
647
648 /* Initialize temporary variables. */
649 prk = hkdf->nx_crypto_hkdf_prk;
650 prk_len = hkdf->nx_crypto_hkdf_prk_size;
651 info = hkdf->nx_crypto_hkdf_info;
652 info_len = hkdf->nx_crypto_hkdf_info_size;
653 temp_T = hkdf->nx_crypto_hkdf_temp_T;
654 temp_T_size = sizeof(hkdf->nx_crypto_hkdf_temp_T);
655 hash_size = hkdf-> nx_crypto_hash_method -> nx_crypto_ICV_size_in_bits >> 3;
656 metadata = hkdf->nx_crypto_hmac_metadata;
657 metadata_size = sizeof(hkdf->nx_crypto_hmac_metadata);
658
659 /* Assign the output size to our HKDF structure. */
660 hkdf->nx_crypto_hkdf_prk_size = hash_size;
661
662 /* Assign T(0), the empty string. */
663 NX_CRYPTO_MEMSET(temp_T, 0, temp_T_size);
664 T_len = 0;
665
666 /* Get our L count for our loop. */
667 N_count = 1 + ((desired_length) / hash_size);
668
669 /* Loop through T(i) to calculate output material (OKM).
670 * NOTE: We start at 1 so the counter is correct. Add one
671 * to N_count to get the full amount of data. */
672 for (i = 1; i < N_count + 1; ++i)
673 {
674 if ((T_len + info_len + 1) > temp_T_size)
675 {
676 return(NX_CRYPTO_SIZE_ERROR);
677 }
678
679 /* Concatenate T(i-1) (in temp_T after the hash above), info, and counter octet to feed into digest. */
680 NX_CRYPTO_MEMCPY(&temp_T[T_len], info, info_len); /* Use case of memcpy is verified. */
681
682 /* Concatenate counter octet. */
683 temp_T[T_len + info_len] = (UCHAR)(i & 0xFF);
684
685 /* Initialize hash method. */
686 if (hmac_method -> nx_crypto_init)
687 {
688 status = hmac_method -> nx_crypto_init(hmac_method,
689 prk,
690 (NX_CRYPTO_KEY_SIZE)(prk_len << 3),
691 &handler,
692 metadata,
693 metadata_size);
694
695 if (status != NX_CRYPTO_SUCCESS)
696 {
697 return(status);
698 }
699 }
700
701 /* The number of bytes we want to hash is a combination of T_len (0 or <hash size>)
702 the length of "info", and add 1 for the counter octet. */
703 T_bytes_to_hash = T_len + info_len + 1;
704
705 /* Calculate T(i) = HMAC(PRK, T(i-1) | info | i) */
706 status = hmac_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
707 handler,
708 hmac_method,
709 prk,
710 (NX_CRYPTO_KEY_SIZE)(prk_len << 3),
711 temp_T,
712 T_bytes_to_hash,
713 NX_CRYPTO_NULL,
714 temp_T,
715 temp_T_size,
716 metadata,
717 metadata_size,
718 NX_CRYPTO_NULL,
719 NX_CRYPTO_NULL);
720
721 if (status != NX_CRYPTO_SUCCESS)
722 {
723 return(status);
724 }
725
726 /* Updated the length of T(i) */
727 T_len = hash_size;
728
729 /* Get our output offset. */
730 offset = (i - 1) * hash_size;
731
732 /* Output block is the size of the digest unless the remaining
733 desired length is smaller than the digest length. */
734 if ((desired_length - offset) < hash_size)
735 {
736 output_len = (desired_length - offset);
737 }
738 else
739 {
740 output_len = hash_size;
741 }
742
743 /* Make sure we only copy the desired data length into the output. */
744 if (hash_size > desired_length)
745 {
746 output_len = desired_length;
747 }
748
749 /* Copy T(i) into output. */
750 NX_CRYPTO_MEMCPY(&output[offset], temp_T, output_len); /* Use case of memcpy is verified. */
751
752 }
753
754 return(NX_CRYPTO_SUCCESS);
755
756
757 }
758
759
760
761
762