Lightweight Cryptography Primitives
 All Data Structures Files Functions Variables Typedefs Macros Pages
internal-hmac.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  * HMAC 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 HMAC variant:
28  *
29  * HMAC_ALG_NAME Name of the HMAC algorithm; e.g. ascon_hmac
30  * HMAC_HASH_SIZE Size of the hash output for the underlying algorithm.
31  * HMAC_BLOCK_SIZE Size of the formatted key block for HMAC.
32  * HMAC_STATE Type for the HMAC state; e.g. ascon_hmac_state_t
33  * HMAC_HASH_INIT Name of the hash initialization function.
34  * HMAC_HASH_UPDATE Name of the hash update function.
35  * HMAC_HASH_FINALIZE Name of the hash finalization function.
36  */
37 #if defined(HMAC_ALG_NAME)
38 
39 #define HMAC_CONCAT_INNER(name,suffix) name##suffix
40 #define HMAC_CONCAT(name,suffix) HMAC_CONCAT_INNER(name,suffix)
41 
43 #define HMAC_IPAD 0x36
44 
46 #define HMAC_OPAD 0x5C
47 
56 static void HMAC_CONCAT(HMAC_ALG_NAME,_xor_pad)
57  (unsigned char *out, const unsigned char *in,
58  size_t size, unsigned char pad)
59 {
60  while (size > 0) {
61  *out++ = *in++ ^ pad;
62  --size;
63  }
64 }
65 
74 static void HMAC_CONCAT(HMAC_ALG_NAME,_absorb_key)
75  (HMAC_STATE *state, const unsigned char *key, size_t keylen,
76  unsigned char pad)
77 {
78  unsigned char temp[HMAC_HASH_SIZE];
79  size_t posn, len;
80 
81  /* Break the key up into smaller chunks and XOR it with "pad".
82  * We do it this way to avoid having a large buffer on the
83  * stack of size HMAC_BLOCK_SIZE. */
84  if (keylen <= HMAC_BLOCK_SIZE) {
85  HMAC_HASH_INIT(state);
86  posn = 0;
87  while (keylen > 0) {
88  len = keylen - posn;
89  if (len > HMAC_HASH_SIZE)
90  len = HMAC_HASH_SIZE;
91  HMAC_CONCAT(HMAC_ALG_NAME,_xor_pad)(temp, key, len, pad);
92  HMAC_HASH_UPDATE(state, temp, len);
93  posn += len;
94  key += len;
95  keylen -= len;
96  }
97  } else {
98  /* Hash long keys down first and then absorb */
99  HMAC_HASH_INIT(state);
100  HMAC_HASH_UPDATE(state, key, keylen);
101  HMAC_HASH_FINALIZE(state, temp);
102  HMAC_CONCAT(HMAC_ALG_NAME,_xor_pad)(temp, temp, HMAC_HASH_SIZE, pad);
103  HMAC_HASH_INIT(state);
104  HMAC_HASH_UPDATE(state, temp, HMAC_HASH_SIZE);
105  posn = HMAC_HASH_SIZE;
106  }
107 
108  /* Pad the rest of the block with the padding value */
109  memset(temp, pad, sizeof(temp));
110  while (posn < HMAC_BLOCK_SIZE) {
111  len = HMAC_BLOCK_SIZE - posn;
112  if (len > HMAC_HASH_SIZE)
113  len = HMAC_HASH_SIZE;
114  HMAC_HASH_UPDATE(state, temp, len);
115  posn += len;
116  }
117 }
118 
119 void HMAC_ALG_NAME
120  (unsigned char *out,
121  const unsigned char *key, size_t keylen,
122  const unsigned char *in, size_t inlen)
123 {
124  HMAC_STATE state;
125  HMAC_CONCAT(HMAC_ALG_NAME,_absorb_key)(&state, key, keylen, HMAC_IPAD);
126  HMAC_HASH_UPDATE(&state, in, inlen);
127  HMAC_CONCAT(HMAC_ALG_NAME,_finalize)(&state, key, keylen, out);
128  aead_clean(&state, sizeof(state));
129 }
130 
131 void HMAC_CONCAT(HMAC_ALG_NAME,_init)
132  (HMAC_STATE *state, const unsigned char *key, size_t keylen)
133 {
134  HMAC_CONCAT(HMAC_ALG_NAME,_absorb_key)(state, key, keylen, HMAC_IPAD);
135 }
136 
137 void HMAC_CONCAT(HMAC_ALG_NAME,_update)
138  (HMAC_STATE *state, const unsigned char *in, size_t inlen)
139 {
140  HMAC_HASH_UPDATE(state, in, inlen);
141 }
142 
143 void HMAC_CONCAT(HMAC_ALG_NAME,_finalize)
144  (HMAC_STATE *state, const unsigned char *key, size_t keylen,
145  unsigned char *out)
146 {
147  unsigned char temp[HMAC_HASH_SIZE];
148  HMAC_HASH_FINALIZE(state, temp);
149  HMAC_CONCAT(HMAC_ALG_NAME,_absorb_key)(state, key, keylen, HMAC_OPAD);
150  HMAC_HASH_UPDATE(state, temp, HMAC_HASH_SIZE);
151  HMAC_HASH_FINALIZE(state, out);
152  aead_clean(temp, sizeof(temp));
153 }
154 
155 #endif /* HMAC_ALG_NAME */
156 
157 /* Now undefine everything so that we can include this file again for
158  * another variant on the HMAC algorithm */
159 #undef HMAC_ALG_NAME
160 #undef HMAC_HASH_SIZE
161 #undef HMAC_BLOCK_SIZE
162 #undef HMAC_STATE
163 #undef HMAC_HASH_INIT
164 #undef HMAC_HASH_UPDATE
165 #undef HMAC_HASH_FINALIZE
166 #undef HMAC_CONCAT_INNER
167 #undef HMAC_CONCAT
168 #undef HMAC_IPAD
169 #undef HMAC_OPAD