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 /** Transport Layer Security (TLS) - PHASH function */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 #include "nx_crypto_phash.h"
24
25 /**************************************************************************/
26 /* */
27 /* FUNCTION RELEASE */
28 /* */
29 /* _nx_crypto_phash PORTABLE C */
30 /* 6.1 */
31 /* AUTHOR */
32 /* */
33 /* Timothy Stapko, Microsoft Corporation */
34 /* */
35 /* DESCRIPTION */
36 /* */
37 /* This function implements phash for the crypto module. */
38 /* */
39 /* INPUT */
40 /* */
41 /* phash phash control block */
42 /* output Pointer to output buffer */
43 /* desired_length Number of bytes to return */
44 /* */
45 /* OUTPUT */
46 /* */
47 /* status Completion status */
48 /* */
49 /* CALLS */
50 /* */
51 /* None */
52 /* */
53 /* CALLED BY */
54 /* */
55 /* Application */
56 /* */
57 /* RELEASE HISTORY */
58 /* */
59 /* DATE NAME DESCRIPTION */
60 /* */
61 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
62 /* 09-30-2020 Timothy Stapko Modified comment(s), improved */
63 /* buffer length verification, */
64 /* verified memcpy use cases, */
65 /* and updated constants, */
66 /* resulting in version 6.1 */
67 /* */
68 /**************************************************************************/
_nx_crypto_phash(NX_CRYPTO_PHASH * phash,UCHAR * output,UINT desired_length)69 NX_CRYPTO_KEEP UINT _nx_crypto_phash(NX_CRYPTO_PHASH *phash, UCHAR *output, UINT desired_length)
70 {
71 UINT offset; /* point to the memory for the coming hmac data */
72 UINT hash_size; /* the length of hmac output */
73 UINT output_len; /* desired output length of hmac */
74 UINT status;
75 /* A(i) */
76 UCHAR *temp_A;
77 UINT temp_A_size;
78 /* secret */
79 UCHAR *secret;
80 UINT secret_len;
81 /* seed */
82 UCHAR *seed;
83 UINT seed_len;
84 /* metadata */
85 UCHAR *metadata;
86 UINT metadata_size;
87 /* hmac output size */
88 UCHAR *hmac_output;
89 UINT hmac_output_size;
90 UINT A_len; /* the length of current A(i) */
91 UINT remaining_len, i; /* remaining length of data to be generated. */
92 VOID *handler = NX_CRYPTO_NULL;
93 NX_CRYPTO_METHOD *hash_method = phash -> nx_crypto_hmac_method;
94
95 NX_CRYPTO_STATE_CHECK
96
97 /* Validate pointers. */
98 if (hash_method == NX_CRYPTO_NULL
99 || hash_method -> nx_crypto_operation == NX_CRYPTO_NULL
100 || hash_method -> nx_crypto_cleanup == NX_CRYPTO_NULL
101 || output == NX_CRYPTO_NULL)
102 {
103 return(NX_CRYPTO_INVALID_PARAMETER);
104 }
105
106 /* Initialize temporary variables. */
107 secret = phash -> nx_crypto_phash_secret;
108 secret_len = phash -> nx_crypto_phash_secret_length;
109 seed = phash -> nx_crypto_phash_seed;
110 seed_len = phash -> nx_crypto_phash_seed_length;
111 temp_A = phash -> nx_crypto_phash_temp_A;
112 temp_A_size = phash -> nx_crypto_phash_temp_A_size;
113 hash_size = hash_method -> nx_crypto_ICV_size_in_bits >> 3;
114 metadata = phash -> nx_crypto_hmac_metadata;
115 metadata_size = phash -> nx_crypto_hmac_metadata_size;
116 hmac_output = phash -> nx_crypto_hmac_output;
117 hmac_output_size = phash -> nx_crypto_hmac_output_size;
118
119 if (hash_size > hmac_output_size)
120 {
121 return(NX_CRYPTO_INVALID_PARAMETER);
122 }
123
124 if (seed_len > temp_A_size)
125 {
126 return(NX_CRYPTO_SIZE_ERROR);
127 }
128
129 /* Assign the seed as A(0). */
130 NX_CRYPTO_MEMSET(temp_A, 0, temp_A_size);
131 NX_CRYPTO_MEMCPY(temp_A, seed, seed_len); /* Use case of memcpy is verified. */
132 A_len = phash -> nx_crypto_phash_seed_length;
133
134 remaining_len = desired_length;
135 for (offset = 0; offset < desired_length; offset += hash_size)
136 {
137 /* Calculate A(i) */
138 if (hash_method -> nx_crypto_init)
139 {
140 status = hash_method -> nx_crypto_init(hash_method,
141 secret,
142 (NX_CRYPTO_KEY_SIZE)(secret_len << 3),
143 &handler,
144 metadata,
145 metadata_size);
146
147 if(status != NX_CRYPTO_SUCCESS)
148 {
149 return(status);
150 }
151 }
152
153 status = hash_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
154 handler,
155 hash_method,
156 secret,
157 (NX_CRYPTO_KEY_SIZE)(secret_len << 3),
158 temp_A,
159 A_len,
160 NX_CRYPTO_NULL,
161 temp_A,
162 temp_A_size,
163 metadata,
164 metadata_size,
165 NX_CRYPTO_NULL,
166 NX_CRYPTO_NULL);
167
168 if(status != NX_CRYPTO_SUCCESS)
169 {
170 return(status);
171 }
172
173 /* Updated the length of A(i) */
174 A_len = hash_size;
175
176 if ((A_len + seed_len) > temp_A_size)
177 {
178 return(NX_CRYPTO_SIZE_ERROR);
179 }
180
181 /* Concatenate A[i] and seed to feed into digest. */
182 NX_CRYPTO_MEMCPY(&temp_A[A_len], seed, seed_len); /* Use case of memcpy is verified. */
183
184 /* Output block is the size of the digest unless the remaining
185 desired length is smaller than the digest length. */
186 if (remaining_len < hash_size)
187 {
188 output_len = remaining_len;
189 }
190 else
191 {
192 output_len = hash_size;
193 }
194
195 /* Calculate p-hash block, store in output. */
196 status = hash_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
197 handler,
198 hash_method,
199 secret,
200 (NX_CRYPTO_KEY_SIZE)(secret_len << 3),
201 temp_A,
202 A_len + seed_len,
203 NX_CRYPTO_NULL,
204 hmac_output,
205 output_len,
206 metadata,
207 metadata_size,
208 NX_CRYPTO_NULL,
209 NX_CRYPTO_NULL);
210
211 if(status != NX_CRYPTO_SUCCESS)
212 {
213 return(status);
214 }
215
216 /* Append the hmac result to the output. */
217 for (i = 0; i < output_len; i++)
218 {
219 output[offset + i] ^= hmac_output[i];
220 }
221
222 /* Adjust our remaining length by the number of bytes written. */
223 remaining_len -= hash_size;
224
225 status = hash_method -> nx_crypto_cleanup(metadata);
226
227 if(status != NX_CRYPTO_SUCCESS)
228 {
229 return(status);
230 }
231 }
232
233 return(NX_CRYPTO_SUCCESS);
234 }
235