Lightweight Cryptography Primitives
 All Data Structures Files Functions Variables Typedefs Macros Pages
internal-kmac.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  * KMAC for a specific underlying XOF algorithm. We expect a number of
26  * macros to be defined before this file is included to configure the
27  * underlying KMAC variant:
28  *
29  * KMAC_ALG_NAME Name of the KMAC algorithm; e.g. ascon_hmac
30  * KMAC_SIZE Size of the default KMAC output.
31  * KMAC_STATE Type for the KMAC state; e.g. ascon_hmac_state_t
32  * KMAC_RATE Rate for the underlying permutation for padding.
33  * KMAC_XOF_INIT Name of the XOF initialization function.
34  * KMAC_XOF_PREINIT Name of the XOF precomputed initialization function.
35  * KMAC_XOF_ABSORB Name of the XOF absorb function.
36  * KMAC_XOF_SQUEEZE Name of the XOF squeeze function.
37  * KMAC_XOF_PAD Name of the XOF function to zero-pad to a
38  * multiple of the rate block size.
39  * KMAC_XOF_IS_ABSORBING(state) Checks to see if the underlying XOF state
40  * is still in absorbing mode.
41  */
42 #if defined(KMAC_ALG_NAME)
43 
44 #define KMAC_CONCAT_INNER(name,suffix) name##suffix
45 #define KMAC_CONCAT(name,suffix) KMAC_CONCAT_INNER(name,suffix)
46 
47 void KMAC_ALG_NAME
48  (const unsigned char *key, size_t keylen,
49  const unsigned char *in, size_t inlen,
50  const unsigned char *custom, size_t customlen,
51  unsigned char *out, size_t outlen)
52 {
53  KMAC_STATE state;
54  KMAC_CONCAT(KMAC_ALG_NAME,_init)(&state, key, keylen, custom, customlen);
55  KMAC_XOF_ABSORB(&state, in, inlen);
56  KMAC_CONCAT(KMAC_ALG_NAME,_set_output_length)(&state, outlen);
57  KMAC_XOF_SQUEEZE(&state, out, outlen);
58  aead_clean(&state, sizeof(state));
59 }
60 
69 static size_t KMAC_CONCAT(KMAC_ALG_NAME,_encode_length)
70  (unsigned char buf[sizeof(size_t) + 1], size_t value)
71 {
72  uint64_t val = value * 8ULL;
73  if (value) {
74  uint64_t temp = val;
75  size_t size = 0;
76  size_t posn;
77  while (temp != 0) {
78  ++size;
79  temp >>= 8;
80  }
81  buf[0] = (unsigned char)size;
82  for (posn = 1; posn <= size; ++posn)
83  buf[posn] = (unsigned char)(val >> ((size - posn) * 8));
84  return size + 1;
85  } else {
86  buf[0] = 0x01;
87  buf[1] = 0x00;
88  return 2;
89  }
90 }
91 
92 void KMAC_CONCAT(KMAC_ALG_NAME,_init)
93  (KMAC_STATE *state, const unsigned char *key, size_t keylen,
94  const unsigned char *custom, size_t customlen)
95 {
96  unsigned char buf[sizeof(uint64_t) + 1];
97  size_t len;
98 
99  /* Rate declaration as a prefix-encoded length value, followed by the
100  * function name, which is the length-prefixed string "KMAC" */
101  static unsigned char const kmac_prefix[] = {
102  0x01, KMAC_RATE
103 #if !defined(KMAC_XOF_PREINIT)
104  , 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43
105 #endif
106  };
107 
108  /* Initialize the XOF state and absorb the prefix. If we have a
109  * precompute function, then use it to shortcut the process. */
110 #if defined(KMAC_XOF_PREINIT)
111  KMAC_XOF_PREINIT(state);
112 #else
113  KMAC_XOF_INIT(state);
114  KMAC_XOF_ABSORB(state, kmac_prefix, sizeof(kmac_prefix));
115 #endif
116 
117  /* Absorb the customization string and pad */
118  len = KMAC_CONCAT(KMAC_ALG_NAME,_encode_length)(buf, customlen);
119  KMAC_XOF_ABSORB(state, buf, len);
120  KMAC_XOF_ABSORB(state, custom, customlen);
121  KMAC_XOF_PAD(state);
122 
123  /* Absorb the key and pad */
124  KMAC_XOF_ABSORB(state, kmac_prefix, 2); /* Just the rate this time */
125  len = KMAC_CONCAT(KMAC_ALG_NAME,_encode_length)(buf, keylen);
126  KMAC_XOF_ABSORB(state, buf, len);
127  KMAC_XOF_ABSORB(state, key, keylen);
128  KMAC_XOF_PAD(state);
129 }
130 
131 void KMAC_CONCAT(KMAC_ALG_NAME,_absorb)
132  (KMAC_STATE *state, const unsigned char *in, size_t inlen)
133 {
134  KMAC_XOF_ABSORB(state, in, inlen);
135 }
136 
144 static void KMAC_CONCAT(KMAC_ALG_NAME,_encode_output_length)
145  (KMAC_STATE *state, size_t outlen)
146 {
147  /* Similar to encode_length() but the length prefix is now a suffix */
148  unsigned char buf[sizeof(uint64_t) + 1];
149  size_t len = KMAC_CONCAT(KMAC_ALG_NAME,_encode_length)(buf, outlen);
150  KMAC_XOF_ABSORB(state, buf + 1, len - 1);
151  KMAC_XOF_ABSORB(state, buf, 1);
152 }
153 
154 void KMAC_CONCAT(KMAC_ALG_NAME,_set_output_length)
155  (KMAC_STATE *state, size_t outlen)
156 {
157  if (KMAC_XOF_IS_ABSORBING(state)) {
158  /* Encode the desired output length and absorb it into the input */
159  KMAC_CONCAT(KMAC_ALG_NAME,_encode_output_length)(state, outlen);
160 
161  /* Switch the underlying XOF state into squeezing mode */
162  KMAC_XOF_SQUEEZE(state, 0, 0);
163  }
164 }
165 
166 void KMAC_CONCAT(KMAC_ALG_NAME,_squeeze)
167  (KMAC_STATE *state, unsigned char *out, size_t outlen)
168 {
169  if (KMAC_XOF_IS_ABSORBING(state)) {
170  /* We are still in the absorb phase, so set the desired
171  * output length to arbitrary */
172  KMAC_CONCAT(KMAC_ALG_NAME,_encode_output_length)(state, 0);
173  }
174  KMAC_XOF_SQUEEZE(state, out, outlen);
175 }
176 
177 void KMAC_CONCAT(KMAC_ALG_NAME,_finalize)
178  (KMAC_STATE *state, unsigned char out[KMAC_SIZE])
179 {
180  if (KMAC_XOF_IS_ABSORBING(state)) {
181  /* We are still in the absorb phase, so set the desired
182  * output length now */
183  KMAC_CONCAT(KMAC_ALG_NAME,_encode_output_length)(state, KMAC_SIZE);
184  }
185  KMAC_XOF_SQUEEZE(state, out, KMAC_SIZE);
186 }
187 
188 #endif /* KMAC_ALG_NAME */
189 
190 /* Now undefine everything so that we can include this file again for
191  * another variant on the KMAC algorithm */
192 #undef KMAC_ALG_NAME
193 #undef KMAC_SIZE
194 #undef KMAC_STATE
195 #undef KMAC_RATE
196 #undef KMAC_XOF_INIT
197 #undef KMAC_XOF_PREINIT
198 #undef KMAC_XOF_ABSORB
199 #undef KMAC_XOF_SQUEEZE
200 #undef KMAC_XOF_PAD
201 #undef KMAC_XOF_IS_ABSORBING
202 #undef KMAC_CONCAT_INNER
203 #undef KMAC_CONCAT