Lightweight Cryptography Primitives
 All Data Structures Files Functions Variables Typedefs Macros Pages
internal-hkdf.h
1 /*
2  * Copyright (C) 2021 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * The contents of this header file expand out to the full implementation of
25  * HKDF for a specific underlying hash algorithm. We expect a number of
26  * macros to be defined before this file is included to configure the
27  * underlying HKDF variant:
28  *
29  * HKDF_ALG_NAME Name of the HKDF algorithm; e.g. ascon_hkdf
30  * HKDF_STATE Type for the HKDF state; e.g. ascon_khdf_state_t
31  * HKDF_HMAC_SIZE Size of the output for the HMAC algorithm.
32  * HKDF_HMAC_STATE Type for the HMAC state; e.g. ascon_hmac_state_t
33  * HKDF_HMAC_INIT Name of the HMAC initialization function.
34  * HKDF_HMAC_UPDATE Name of the HMAC update function.
35  * HKDF_HMAC_FINALIZE Name of the HMAC finalization function.
36  */
37 #if defined(HKDF_ALG_NAME)
38 
39 #define HKDF_CONCAT_INNER(name,suffix) name##suffix
40 #define HKDF_CONCAT(name,suffix) HKDF_CONCAT_INNER(name,suffix)
41 
42 int HKDF_ALG_NAME
43  (unsigned char *out, size_t outlen,
44  const unsigned char *key, size_t keylen,
45  const unsigned char *salt, size_t saltlen,
46  const unsigned char *info, size_t infolen)
47 {
48  HKDF_STATE state;
49  if (outlen > (size_t)(HKDF_HMAC_SIZE * 255))
50  return -1;
51  HKDF_CONCAT(HKDF_ALG_NAME,_extract)(&state, key, keylen, salt, saltlen);
52  HKDF_CONCAT(HKDF_ALG_NAME,_expand)(&state, info, infolen, out, outlen);
53  aead_clean(&state, sizeof(state));
54  return 0;
55 }
56 
57 void HKDF_CONCAT(HKDF_ALG_NAME,_extract)
58  (HKDF_STATE *state,
59  const unsigned char *key, size_t keylen,
60  const unsigned char *salt, size_t saltlen)
61 {
62  HKDF_HMAC_STATE hmac;
63  HKDF_HMAC_INIT(&hmac, salt, saltlen);
64  HKDF_HMAC_UPDATE(&hmac, key, keylen);
65  HKDF_HMAC_FINALIZE(&hmac, salt, saltlen, state->prk);
66  state->counter = 1;
67  state->posn = HKDF_HMAC_SIZE;
68  aead_clean(&hmac, sizeof(hmac));
69 }
70 
71 int HKDF_CONCAT(HKDF_ALG_NAME,_expand)
72  (HKDF_STATE *state,
73  const unsigned char *info, size_t infolen,
74  unsigned char *out, size_t outlen)
75 {
76  HKDF_HMAC_STATE hmac;
77  size_t len;
78 
79  /* Deal with left-over data from the last output block */
80  len = HKDF_HMAC_SIZE - state->posn;
81  if (len > outlen)
82  len = outlen;
83  memcpy(out, state->out + state->posn, len);
84  out += len;
85  outlen -= len;
86  state->posn += len;
87 
88  /* Squeeze out the data one block at a time */
89  while (outlen > 0) {
90  /* Have we squeezed out too many blocks already? */
91  if (state->counter == 0) {
92  memset(out, 0, outlen); /* Zero the rest of the output data */
93  aead_clean(&hmac, sizeof(hmac));
94  return -1;
95  }
96 
97  /* Squeeze out the next block of data */
98  HKDF_HMAC_INIT(&hmac, state->prk, sizeof(state->prk));
99  if (state->counter != 1)
100  HKDF_HMAC_UPDATE(&hmac, state->out, sizeof(state->out));
101  HKDF_HMAC_UPDATE(&hmac, info, infolen);
102  HKDF_HMAC_UPDATE(&hmac, &(state->counter), 1);
103  HKDF_HMAC_FINALIZE(&hmac, state->prk, sizeof(state->prk), state->out);
104  ++(state->counter);
105 
106  /* Copy the data to the output buffer */
107  len = HKDF_HMAC_SIZE;
108  if (len > outlen)
109  len = outlen;
110  memcpy(out, state->out, len);
111  state->posn = len;
112  out += len;
113  outlen -= len;
114  }
115  aead_clean(&hmac, sizeof(hmac));
116  return 0;
117 }
118 
119 void HKDF_CONCAT(HKDF_ALG_NAME,_free)(HKDF_STATE *state)
120 {
121  aead_clean(state, sizeof(HKDF_STATE));
122 }
123 
124 #endif /* HKDF_ALG_NAME */
125 
126 /* Now undefine everything so that we can include this file again for
127  * another variant on the HKDF algorithm */
128 #undef HKDF_ALG_NAME
129 #undef HKDF_STATE
130 #undef HKDF_HMAC_SIZE
131 #undef HKDF_HMAC_STATE
132 #undef HKDF_HMAC_INIT
133 #undef HKDF_HMAC_UPDATE
134 #undef HKDF_HMAC_FINALIZE