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