kmac.c
Go to the documentation of this file.
1 /**
2  * @file kmac.c
3  * @brief KMAC (Keccak Message Authentication Code)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Keccak Message Authentication Code (KMAC) algorithm is a PRF and keyed
30  * hash function based on Keccak. KMAC has two variants, KMAC128 and KMAC256,
31  * built from cSHAKE128 and cSHAKE256, respectively
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.4.4
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/crypto.h"
42 #include "mac/kmac.h"
43 
44 //Check crypto library configuration
45 #if (KMAC_SUPPORT == ENABLED)
46 
47 //KMAC128 object identifier (2.16.840.1.101.3.4.2.19)
48 const uint8_t kmac128Oid[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x13};
49 //KMAC256 object identifier (2.16.840.1.101.3.4.2.20)
50 const uint8_t kmac256Oid[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x14};
51 
52 
53 /**
54  * @brief Compute KMAC message authentication code
55  * @param[in] strength Number of bits of security (128 for KMAC128 and
56  * 256 for KMAC256)
57  * @param[in] key Pointer to the secret key (K)
58  * @param[in] keyLen Length of the secret key
59  * @param[in] data Pointer to the input message (X)
60  * @param[in] dataLen Length of the input data
61  * @param[in] custom Customization string (S)
62  * @param[in] customLen Length of the customization string
63  * @param[out] mac Calculated MAC value
64  * @param[in] macLen Expected length of the MAC (L)
65  * @return Error code
66  **/
67 
68 error_t kmacCompute(uint_t strength, const void *key, size_t keyLen,
69  const void *data, size_t dataLen, const char_t *custom, size_t customLen,
70  uint8_t *mac, size_t macLen)
71 {
72  error_t error;
73 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
74  KmacContext *context;
75 #else
76  KmacContext context[1];
77 #endif
78 
79 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
80  //Allocate a memory buffer to hold the KMAC context
81  context = cryptoAllocMem(sizeof(KmacContext));
82  //Failed to allocate memory?
83  if(context == NULL)
84  return ERROR_OUT_OF_MEMORY;
85 #endif
86 
87  //Initialize the KMAC context
88  error = kmacInit(context, strength, key, keyLen, custom, customLen);
89 
90  //Check status code
91  if(!error)
92  {
93  //Digest the message
94  kmacUpdate(context, data, dataLen);
95  //Finalize the KMAC computation
96  error = kmacFinal(context, mac, macLen);
97  }
98 
99 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
100  //Free previously allocated memory
101  cryptoFreeMem(context);
102 #endif
103 
104  //Return status code
105  return error;
106 }
107 
108 
109 /**
110  * @brief Initialize KMAC calculation
111  * @param[in] context Pointer to the KMAC context to initialize
112  * @param[in] strength Number of bits of security (128 for KMAC128 and
113  * 256 for KMAC256)
114  * @param[in] key Pointer to the secret key (K)
115  * @param[in] keyLen Length of the secret key
116  * @param[in] custom Customization string (S)
117  * @param[in] customLen Length of the customization string
118  * @return Error code
119  **/
120 
121 error_t kmacInit(KmacContext *context, uint_t strength, const void *key,
122  size_t keyLen, const char_t *custom, size_t customLen)
123 {
124  error_t error;
125  size_t i;
126  size_t n;
127  size_t rate;
128  uint8_t buffer[sizeof(size_t) + 1];
129 
130  //Make sure the KMAC context is valid
131  if(context == NULL)
133 
134  //Make sure the supplied key is valid
135  if(key == NULL && keyLen != 0)
137 
138  //Initialize cSHAKE context
139  error = cshakeInit(&context->cshakeContext, strength, "KMAC", 4, custom,
140  customLen);
141  //Any error to report?
142  if(error)
143  return error;
144 
145  //The rate of the underlying Keccak sponge function is 168 for KMAC128
146  //and 136 for KMAC256
147  rate = context->cshakeContext.keccakContext.blockSize;
148 
149  //Absorb the string representation of the rate
150  cshakeLeftEncode(rate, buffer, &n);
151  cshakeAbsorb(&context->cshakeContext, buffer, n);
152  i = n;
153 
154  //Absorb the string representation of K
155  cshakeLeftEncode(keyLen * 8, buffer, &n);
156  cshakeAbsorb(&context->cshakeContext, buffer, n);
157  cshakeAbsorb(&context->cshakeContext, key, keyLen);
158  i += n + keyLen;
159 
160  //The padding string consists of bytes set to zero
161  buffer[0] = 0;
162 
163  //Pad the result with zeros until it is a byte string whose length in
164  //bytes is a multiple of the rate
165  while((i % rate) != 0)
166  {
167  //Absorb the padding string
168  cshakeAbsorb(&context->cshakeContext, buffer, 1);
169  i++;
170  }
171 
172  //Successful initialization
173  return NO_ERROR;
174 }
175 
176 
177 /**
178  * @brief Update the KMAC context with a portion of the message being hashed
179  * @param[in] context Pointer to the KMAC context
180  * @param[in] data Pointer to the input data
181  * @param[in] dataLen Length of the buffer
182  **/
183 
184 void kmacUpdate(KmacContext *context, const void *data, size_t dataLen)
185 {
186  //Absorb the input data
187  cshakeAbsorb(&context->cshakeContext, data, dataLen);
188 }
189 
190 
191 /**
192  * @brief Finish the KMAC calculation
193  * @param[in] context Pointer to the KMAC context
194  * @param[out] mac Calculated MAC value
195  * @param[in] macLen Expected length of the MAC (L)
196  * @return Error code
197  **/
198 
199 error_t kmacFinal(KmacContext *context, uint8_t *mac, size_t macLen)
200 {
201  size_t n;
202  uint8_t buffer[sizeof(size_t) + 1];
203 
204  //Make sure the KMAC context is valid
205  if(context == NULL)
207 
208  //When the requested output length is zero, KMAC returns the empty string
209  //as the output
210  if(mac == NULL && macLen != 0)
212 
213  //Absorb the string representation of L
214  kmacRightEncode(macLen * 8, buffer, &n);
215  cshakeAbsorb(&context->cshakeContext, buffer, n);
216 
217  //Finish absorbing phase
218  cshakeFinal(&context->cshakeContext);
219  //Extract data from the squeezing phase
220  cshakeSqueeze(&context->cshakeContext, mac, macLen);
221 
222  //Successful processing
223  return NO_ERROR;
224 }
225 
226 
227 /**
228  * @brief Release KMAC context
229  * @param[in] context Pointer to the KMAC context
230  **/
231 
232 void kmacDeinit(KmacContext *context)
233 {
234  //Make sure the KMAC context is valid
235  if(context != NULL)
236  {
237  //Clear KMAC context
238  osMemset(context, 0, sizeof(KmacContext));
239  }
240 }
241 
242 
243 /**
244  * @brief Encode integer as byte string
245  * @param[in] value Value of the integer to be encoded
246  * @param[out] buffer Buffer where to store the byte string representation
247  * @param[out] length Length of the resulting byte string
248  **/
249 
250 void kmacRightEncode(size_t value, uint8_t *buffer, size_t *length)
251 {
252  size_t i;
253  size_t n;
254  size_t temp;
255 
256  //Get the value of the integer to be encoded
257  temp = value;
258 
259  //Let n be the smallest positive integer for which 2^(8*n) > x
260  for(n = 1; n < sizeof(size_t) && (temp >> 8) != 0; n++)
261  {
262  temp >>= 8;
263  }
264 
265  //Encode O(1) || ... || O(n)
266  for(i = 0; i < n; i++)
267  {
268  buffer[i] = value >> ((n - i - 1) * 8);
269  }
270 
271  //Encode O(n+1)
272  buffer[i] = n;
273 
274  //Return the length of the byte string representation
275  *length = n + 1;
276 }
277 
278 #endif
error_t cshakeInit(CshakeContext *context, uint_t strength, const char_t *name, size_t nameLen, const char_t *custom, size_t customLen)
Initialize cSHAKE context.
Definition: cshake.c:124
error_t kmacInit(KmacContext *context, uint_t strength, const void *key, size_t keyLen, const char_t *custom, size_t customLen)
Initialize KMAC calculation.
Definition: kmac.c:121
KeccakContext keccakContext
Definition: cshake.h:52
uint8_t data[]
Definition: ethernet.h:222
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
error_t kmacCompute(uint_t strength, const void *key, size_t keyLen, const void *data, size_t dataLen, const char_t *custom, size_t customLen, uint8_t *mac, size_t macLen)
Compute KMAC message authentication code.
Definition: kmac.c:68
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void kmacDeinit(KmacContext *context)
Release KMAC context.
Definition: kmac.c:232
error_t
Error codes.
Definition: error.h:43
void cshakeFinal(CshakeContext *context)
Finish absorbing phase.
Definition: cshake.c:220
const uint8_t kmac128Oid[9]
Definition: kmac.c:48
General definitions for cryptographic algorithms.
KMAC (Keccak Message Authentication Code)
uint8_t length
Definition: tcp.h:368
void cshakeAbsorb(CshakeContext *context, const void *input, size_t length)
Absorb data.
Definition: cshake.c:208
uint32_t dataLen
Definition: sftp_common.h:229
void cshakeLeftEncode(size_t value, uint8_t *buffer, size_t *length)
Encode integer as byte string.
Definition: cshake.c:262
char char_t
Definition: compiler_port.h:48
void kmacUpdate(KmacContext *context, const void *data, size_t dataLen)
Update the KMAC context with a portion of the message being hashed.
Definition: kmac.c:184
uint8_t n
uint_t blockSize
Definition: keccak.h:121
void kmacRightEncode(size_t value, uint8_t *buffer, size_t *length)
Encode integer as byte string.
Definition: kmac.c:250
#define cryptoFreeMem(p)
Definition: crypto.h:791
const uint8_t kmac256Oid[9]
Definition: kmac.c:50
uint8_t value[]
Definition: tcp.h:369
#define cryptoAllocMem(size)
Definition: crypto.h:786
error_t kmacFinal(KmacContext *context, uint8_t *mac, size_t macLen)
Finish the KMAC calculation.
Definition: kmac.c:199
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
KMAC algorithm context.
Definition: kmac.h:54
@ NO_ERROR
Success.
Definition: error.h:44
void cshakeSqueeze(CshakeContext *context, uint8_t *output, size_t length)
Extract data from the squeezing phase.
Definition: cshake.c:248
CshakeContext cshakeContext
Definition: kmac.h:55