"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/libcanlock/test/hkdf.c" (23 Aug 2021, 10574 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the last
Fossies "Diffs" side-by-side code changes report for "hkdf.c":
2.4.5_vs_2.6.0.
1 /**************************** hkdf.c ***************************/
2 /***************** See RFC 6234 for details. *******************/
3 /* Copyright (c) 2011 IETF Trust and the persons identified as */
4 /* authors of the code. All rights reserved. */
5 /* See sha.h for terms of use and redistribution. */
6
7 /*
8 * Description:
9 * This file implements the HKDF algorithm (HMAC-based
10 * Extract-and-Expand Key Derivation Function, RFC 5869),
11 * expressed in terms of the various SHA algorithms.
12 *
13 * Note:
14 * Prefix for internal API changed from "hkdf" to "RRFC5869Hkdf".
15 */
16
17 #include "sha.h"
18 #include <string.h>
19 #include <stdlib.h>
20
21 /*
22 * RFC5869Hkdf
23 *
24 * Description:
25 * This function will generate keying material using HKDF.
26 *
27 * Parameters:
28 * whichSha: [in]
29 * One of SHA1, SHA224, SHA256, SHA384, SHA512
30 * salt[ ]: [in]
31 * The optional salt value (a non-secret random value);
32 * if not provided (salt == NULL), it is set internally
33 * to a string of HashLen(whichSha) zeros.
34 * salt_len: [in]
35 * The length of the salt value. (Ignored if salt == NULL.)
36 * ikm[ ]: [in]
37 * Input keying material.
38 * ikm_len: [in]
39 * The length of the input keying material.
40 * info[ ]: [in]
41 * The optional context and application specific information.
42 * If info == NULL or a zero-length string, it is ignored.
43 * info_len: [in]
44 * The length of the optional context and application specific
45 * information. (Ignored if info == NULL.)
46 * okm[ ]: [out]
47 * Where the HKDF is to be stored.
48 * okm_len: [in]
49 * The length of the buffer to hold okm.
50 * okm_len must be <= 255 * USHABlockSize(whichSha)
51 *
52 * Notes:
53 * Calls hkdfExtract() and hkdfExpand().
54 *
55 * Returns:
56 * sha Error Code.
57 *
58 */
59 int RFC5869Hkdf(SHAversion whichSha,
60 const unsigned char *salt, int salt_len,
61 const unsigned char *ikm, int ikm_len,
62 const unsigned char *info, int info_len,
63 uint8_t okm[ ], int okm_len)
64 {
65 uint8_t prk[USHAMaxHashSize];
66 return RFC5869HkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
67 RFC5869HkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
68 info_len, okm, okm_len);
69 }
70
71 /*
72 * RFC5869HkdfExtract
73 *
74 * Description:
75 * This function will perform HKDF extraction.
76 *
77 * Parameters:
78 * whichSha: [in]
79 * One of SHA1, SHA224, SHA256, SHA384, SHA512
80 * salt[ ]: [in]
81 * The optional salt value (a non-secret random value);
82 * if not provided (salt == NULL), it is set internally
83 * to a string of HashLen(whichSha) zeros.
84 * salt_len: [in]
85 * The length of the salt value. (Ignored if salt == NULL.)
86 * ikm[ ]: [in]
87 * Input keying material.
88 * ikm_len: [in]
89 * The length of the input keying material.
90 * prk[ ]: [out]
91 * Array where the HKDF extraction is to be stored.
92 * Must be larger than USHAHashSize(whichSha);
93 *
94 * Returns:
95 * sha Error Code.
96 *
97 */
98 int RFC5869HkdfExtract(SHAversion whichSha,
99 const unsigned char *salt, int salt_len,
100 const unsigned char *ikm, int ikm_len,
101 uint8_t prk[USHAMaxHashSize])
102 {
103 unsigned char nullSalt[USHAMaxHashSize];
104 if (salt == 0) {
105 salt = nullSalt;
106 salt_len = USHAHashSize(whichSha);
107 memset(nullSalt, '\0', salt_len);
108 } else if (salt_len < 0) {
109 return shaBadParam;
110 }
111 return RFC2104Hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
112 }
113
114 /*
115 * RFC5869HkdfExpand
116 *
117 * Description:
118 * This function will perform HKDF expansion.
119 *
120 * Parameters:
121 * whichSha: [in]
122 * One of SHA1, SHA224, SHA256, SHA384, SHA512
123 * prk[ ]: [in]
124 * The pseudo-random key to be expanded; either obtained
125 * directly from a cryptographically strong, uniformly
126 * distributed pseudo-random number generator, or as the
127 * output from hkdfExtract().
128 * prk_len: [in]
129 * The length of the pseudo-random key in prk;
130 * should at least be equal to USHAHashSize(whichSHA).
131 * info[ ]: [in]
132 * The optional context and application specific information.
133 * If info == NULL or a zero-length string, it is ignored.
134 * info_len: [in]
135 * The length of the optional context and application specific
136 * information. (Ignored if info == NULL.)
137 * okm[ ]: [out]
138 * Where the HKDF is to be stored.
139 * okm_len: [in]
140 * The length of the buffer to hold okm.
141 * okm_len must be <= 255 * USHABlockSize(whichSha)
142 *
143 * Returns:
144 * sha Error Code.
145 *
146 */
147 int RFC5869HkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len,
148 const unsigned char *info, int info_len,
149 uint8_t okm[ ], int okm_len)
150 {
151 int hash_len, N;
152 unsigned char T[USHAMaxHashSize];
153 int Tlen, where, i;
154
155 if (info == 0) {
156 info = (const unsigned char *)"";
157 info_len = 0;
158 } else if (info_len < 0) {
159 return shaBadParam;
160 }
161 if (okm_len <= 0) return shaBadParam;
162 if (!okm) return shaBadParam;
163
164 hash_len = USHAHashSize(whichSha);
165 if (prk_len < hash_len) return shaBadParam;
166 N = okm_len / hash_len;
167 if ((okm_len % hash_len) != 0) N++;
168 if (N > 255) return shaBadParam;
169
170 Tlen = 0;
171 where = 0;
172 for (i = 1; i <= N; i++) {
173 HMACContext context;
174 unsigned char c = i;
175 int ret = RFC2104HmacReset(&context, whichSha, prk, prk_len) ||
176 RFC2104HmacInput(&context, T, Tlen) ||
177 RFC2104HmacInput(&context, info, info_len) ||
178 RFC2104HmacInput(&context, &c, 1) ||
179 RFC2104HmacResult(&context, T);
180 if (ret != shaSuccess) return ret;
181 memcpy(okm + where, T,
182 (i != N) ? hash_len : (okm_len - where));
183 where += hash_len;
184 Tlen = hash_len;
185 }
186 return shaSuccess;
187 }
188
189 /*
190 * RFC5869HkdfReset
191 *
192 * Description:
193 * This function will initialize the hkdfContext in preparation
194 * for key derivation using the modular HKDF interface for
195 * arbitrary length inputs.
196 *
197 * Parameters:
198 * context: [in/out]
199 * The context to reset.
200 * whichSha: [in]
201 * One of SHA1, SHA224, SHA256, SHA384, SHA512
202 * salt[ ]: [in]
203 * The optional salt value (a non-secret random value);
204 * if not provided (salt == NULL), it is set internally
205 * to a string of HashLen(whichSha) zeros.
206 * salt_len: [in]
207 * The length of the salt value. (Ignored if salt == NULL.)
208 *
209 * Returns:
210 * sha Error Code.
211 *
212 */
213 int RFC5869HkdfReset(HKDFContext *context, enum SHAversion whichSha,
214 const unsigned char *salt, int salt_len)
215 {
216 unsigned char nullSalt[USHAMaxHashSize];
217 if (!context) return shaNull;
218
219 context->whichSha = whichSha;
220 context->hashSize = USHAHashSize(whichSha);
221 if (salt == 0) {
222 salt = nullSalt;
223 salt_len = context->hashSize;
224 memset(nullSalt, '\0', salt_len);
225 }
226
227 return RFC2104HmacReset(&context->hmacContext, whichSha, salt, salt_len);
228 }
229
230 /*
231 * hkdfInput
232 *
233 * Description:
234 * This function accepts an array of octets as the next portion
235 * of the input keying material. It may be called multiple times.
236 *
237 * Parameters:
238 * context: [in/out]
239 * The HKDF context to update.
240 * ikm[ ]: [in]
241 * An array of octets representing the next portion of
242 * the input keying material.
243 * ikm_len: [in]
244 * The length of ikm.
245 *
246 * Returns:
247 * sha Error Code.
248 *
249 */
250 int RFC5869HkdfInput(HKDFContext *context, const unsigned char *ikm,
251 int ikm_len)
252 {
253 if (!context) return shaNull;
254 if (context->Corrupted) return context->Corrupted;
255 if (context->Computed) return context->Corrupted = shaStateError;
256 return RFC2104HmacInput(&context->hmacContext, ikm, ikm_len);
257 }
258
259 /*
260 * RFC5869HkdfFinalBits
261 *
262 * Description:
263 * This function will add in any final bits of the
264 * input keying material.
265 *
266 * Parameters:
267 * context: [in/out]
268 * The HKDF context to update
269 * ikm_bits: [in]
270 * The final bits of the input keying material, in the upper
271 * portion of the byte. (Use 0b###00000 instead of 0b00000###
272 * to input the three bits ###.)
273 * ikm_bit_count: [in]
274 * The number of bits in message_bits, between 1 and 7.
275 *
276 * Returns:
277 * sha Error Code.
278 */
279 int RFC5869HkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
280 unsigned int ikm_bit_count)
281 {
282 if (!context) return shaNull;
283 if (context->Corrupted) return context->Corrupted;
284 if (context->Computed) return context->Corrupted = shaStateError;
285 return RFC2104HmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
286 }
287
288 /*
289 * RFC5869HkdfResult
290 *
291 * Description:
292 * This function will finish the HKDF extraction and perform the
293 * final HKDF expansion.
294 *
295 * Parameters:
296 * context: [in/out]
297 * The HKDF context to use to calculate the HKDF hash.
298 * prk[ ]: [out]
299 * An optional location to store the HKDF extraction.
300 * Either NULL, or pointer to a buffer that must be
301 * larger than USHAHashSize(whichSha);
302 * info[ ]: [in]
303 * The optional context and application specific information.
304 * If info == NULL or a zero-length string, it is ignored.
305 * info_len: [in]
306 * The length of the optional context and application specific
307 * information. (Ignored if info == NULL.)
308 * okm[ ]: [out]
309 * Where the HKDF is to be stored.
310 * okm_len: [in]
311 * The length of the buffer to hold okm.
312 * okm_len must be <= 255 * USHABlockSize(whichSha)
313 *
314 * Returns:
315 * sha Error Code.
316 *
317 */
318 int RFC5869HkdfResult(HKDFContext *context,
319 uint8_t prk[USHAMaxHashSize],
320 const unsigned char *info, int info_len,
321 uint8_t okm[ ], int okm_len)
322 {
323 uint8_t prkbuf[USHAMaxHashSize];
324 int ret;
325
326 if (!context) return shaNull;
327 if (context->Corrupted) return context->Corrupted;
328 if (context->Computed) return context->Corrupted = shaStateError;
329 if (!okm) return context->Corrupted = shaBadParam;
330 if (!prk) prk = prkbuf;
331
332 ret = RFC2104HmacResult(&context->hmacContext, prk) ||
333 RFC5869HkdfExpand(context->whichSha, prk, context->hashSize, info,
334 info_len, okm, okm_len);
335 context->Computed = 1;
336 return context->Corrupted = ret;
337 }