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