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