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-2026 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.6.6
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 KMAC128_OID[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 KMAC256_OID[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  //Check parameters
80  if(data == NULL && dataLen != 0)
82 
83 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
84  //Allocate a memory buffer to hold the KMAC context
85  context = cryptoAllocMem(sizeof(KmacContext));
86  //Failed to allocate memory?
87  if(context == NULL)
88  return ERROR_OUT_OF_MEMORY;
89 #endif
90 
91  //Initialize the KMAC context
92  error = kmacInit(context, strength, key, keyLen, custom, customLen);
93 
94  //Check status code
95  if(!error)
96  {
97  //Digest the message
98  kmacUpdate(context, data, dataLen);
99  //Finalize the KMAC computation
100  error = kmacFinal(context, mac, macLen);
101  }
102 
103 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
104  //Free previously allocated memory
105  cryptoFreeMem(context);
106 #endif
107 
108  //Return status code
109  return error;
110 }
111 
112 
113 /**
114  * @brief Initialize KMAC calculation
115  * @param[in] context Pointer to the KMAC context to initialize
116  * @param[in] strength Number of bits of security (128 for KMAC128 and
117  * 256 for KMAC256)
118  * @param[in] key Pointer to the secret key (K)
119  * @param[in] keyLen Length of the secret key
120  * @param[in] custom Customization string (S)
121  * @param[in] customLen Length of the customization string
122  * @return Error code
123  **/
124 
125 error_t kmacInit(KmacContext *context, uint_t strength, const void *key,
126  size_t keyLen, const char_t *custom, size_t customLen)
127 {
128  error_t error;
129  size_t i;
130  size_t n;
131  size_t rate;
132  uint8_t buffer[sizeof(size_t) + 1];
133 
134  //Make sure the KMAC context is valid
135  if(context == NULL)
137 
138  //Make sure the supplied key is valid
139  if(key == NULL && keyLen != 0)
141 
142  //Initialize cSHAKE context
143  error = cshakeInit(&context->cshakeContext, strength, "KMAC", 4, custom,
144  customLen);
145  //Any error to report?
146  if(error)
147  return error;
148 
149  //The rate of the underlying Keccak sponge function is 168 for KMAC128
150  //and 136 for KMAC256
151  rate = context->cshakeContext.keccakContext.blockSize;
152 
153  //Absorb the string representation of the rate
154  cshakeLeftEncode(rate, buffer, &n);
155  cshakeAbsorb(&context->cshakeContext, buffer, n);
156  i = n;
157 
158  //Absorb the string representation of K
159  cshakeLeftEncode(keyLen * 8, buffer, &n);
160  cshakeAbsorb(&context->cshakeContext, buffer, n);
161  cshakeAbsorb(&context->cshakeContext, key, keyLen);
162  i += n + keyLen;
163 
164  //The padding string consists of bytes set to zero
165  buffer[0] = 0;
166 
167  //Pad the result with zeros until it is a byte string whose length in
168  //bytes is a multiple of the rate
169  while((i % rate) != 0)
170  {
171  //Absorb the padding string
172  cshakeAbsorb(&context->cshakeContext, buffer, 1);
173  i++;
174  }
175 
176  //Successful initialization
177  return NO_ERROR;
178 }
179 
180 
181 /**
182  * @brief Update the KMAC context with a portion of the message being hashed
183  * @param[in] context Pointer to the KMAC context
184  * @param[in] data Pointer to the input data
185  * @param[in] dataLen Length of the buffer
186  **/
187 
188 void kmacUpdate(KmacContext *context, const void *data, size_t dataLen)
189 {
190  //Absorb the input data
191  cshakeAbsorb(&context->cshakeContext, data, dataLen);
192 }
193 
194 
195 /**
196  * @brief Finish the KMAC calculation
197  * @param[in] context Pointer to the KMAC context
198  * @param[out] mac Calculated MAC value
199  * @param[in] macLen Expected length of the MAC (L)
200  * @return Error code
201  **/
202 
203 error_t kmacFinal(KmacContext *context, uint8_t *mac, size_t macLen)
204 {
205  size_t n;
206  uint8_t buffer[sizeof(size_t) + 1];
207 
208  //Make sure the KMAC context is valid
209  if(context == NULL)
211 
212  //When the requested output length is zero, KMAC returns the empty string
213  //as the output
214  if(mac == NULL && macLen != 0)
216 
217  //Absorb the string representation of L
218  cshakeRightEncode(macLen * 8, buffer, &n);
219  cshakeAbsorb(&context->cshakeContext, buffer, n);
220 
221  //Finish absorbing phase
222  cshakeFinal(&context->cshakeContext);
223  //Extract data from the squeezing phase
224  cshakeSqueeze(&context->cshakeContext, mac, macLen);
225 
226  //Successful processing
227  return NO_ERROR;
228 }
229 
230 
231 /**
232  * @brief Release KMAC context
233  * @param[in] context Pointer to the KMAC context
234  **/
235 
236 void kmacDeinit(KmacContext *context)
237 {
238  //Make sure the KMAC context is valid
239  if(context != NULL)
240  {
241  //Clear KMAC context
242  osMemset(context, 0, sizeof(KmacContext));
243  }
244 }
245 
246 #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
const uint8_t KMAC256_OID[9]
Definition: kmac.c:50
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:125
KeccakContext keccakContext
Definition: cshake.h:52
uint8_t data[]
Definition: ethernet.h:224
@ 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:236
error_t
Error codes.
Definition: error.h:43
void cshakeFinal(CshakeContext *context)
Finish absorbing phase.
Definition: cshake.c:220
General definitions for cryptographic algorithms.
KMAC (Keccak Message Authentication Code)
const uint8_t KMAC128_OID[9]
Definition: kmac.c:48
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:55
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:188
uint8_t n
uint_t blockSize
Definition: keccak.h:119
#define cryptoFreeMem(p)
Definition: crypto.h:966
#define cryptoAllocMem(size)
Definition: crypto.h:961
error_t kmacFinal(KmacContext *context, uint8_t *mac, size_t macLen)
Finish the KMAC calculation.
Definition: kmac.c:203
void cshakeRightEncode(size_t value, uint8_t *buffer, size_t *length)
Encode integer as byte string.
Definition: cshake.c:298
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:141
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