Leancrypto 0.12.0
Post-Quantum Cryptographic Library
Loading...
Searching...
No Matches
lc_kmac.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 - 2024, Stephan Mueller <smueller@chronox.de>
3 *
4 * License: see LICENSE file in root directory
5 *
6 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
7 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
8 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
9 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
10 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
11 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
12 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
13 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
16 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 */
19
20#ifndef LC_KMAC_H
21#define LC_KMAC_H
22
23#include "lc_hash.h"
24#include "lc_rng.h"
25#include "lc_sha3.h"
26#include "lc_memset_secure.h"
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
33struct lc_kmac_ctx {
34 uint8_t final_called : 1;
35 uint8_t rng_initialized : 1;
36 uint8_t *shadow_ctx;
37 struct lc_hash_ctx hash_ctx;
38};
39
40#define LC_KMAC_STATE_SIZE(x) (LC_HASH_STATE_SIZE(x))
41#define LC_KMAC_STATE_SIZE_REINIT(x) (2 * LC_HASH_STATE_SIZE(x))
42#define LC_KMAC_CTX_SIZE(x) (LC_KMAC_STATE_SIZE(x) + sizeof(struct lc_kmac_ctx))
43#define LC_KMAC_CTX_SIZE_REINIT(x) \
44 (LC_KMAC_STATE_SIZE_REINIT(x) + sizeof(struct lc_kmac_ctx))
45
46#define _LC_KMAC_SET_CTX(name, hashname, ctx, offset) \
47 _LC_HASH_SET_CTX((&name->hash_ctx), hashname, ctx, offset); \
48 name->shadow_ctx = NULL
49
50#define LC_KMAC_SET_CTX(name, hashname) \
51 _LC_KMAC_SET_CTX(name, hashname, name, sizeof(struct lc_kmac_ctx))
52
53#define _LC_KMAC_SET_CTX_REINIT(name, hashname, ctx, offset) \
54 _LC_HASH_SET_CTX((&name->hash_ctx), hashname, ctx, offset); \
55 name->shadow_ctx = (uint8_t *)((uint8_t *)ctx + offset + \
56 LC_HASH_STATE_SIZE(hashname))
57
58#define LC_KMAC_SET_CTX_REINIT(name, hashname) \
59 _LC_KMAC_SET_CTX_REINIT(name, hashname, name, \
60 sizeof(struct lc_kmac_ctx))
62
76void lc_kmac_init(struct lc_kmac_ctx *kmac_ctx, const uint8_t *key, size_t klen,
77 const uint8_t *s, size_t slen);
78
88void lc_kmac_reinit(struct lc_kmac_ctx *kmac_ctx);
89
98void lc_kmac_update(struct lc_kmac_ctx *kmac_ctx, const uint8_t *in,
99 size_t inlen);
100
113void lc_kmac_final(struct lc_kmac_ctx *kmac_ctx, uint8_t *mac, size_t maclen);
114
144void lc_kmac_final_xof(struct lc_kmac_ctx *kmac_ctx, uint8_t *mac,
145 size_t maclen);
146
159int lc_kmac_alloc(const struct lc_hash *hash, struct lc_kmac_ctx **kmac_ctx,
160 uint32_t flags);
161
162/*
163 * Support re-initialization of state. You set a key during kmac_init,
164 * perform a full KMAC operation. After a kmac_final, the re-initialization
165 * support allows you to call kmac_reinit and reuse the state for a new
166 * operation without providing the keys again. If in doubt, initialize
167 * the context with re-init support. The difference is that more memory is
168 * allocated to retain the initialized state.
169 */
170#define LC_KMAC_FLAGS_SUPPORT_REINIT (1 << 0)
171
177void lc_kmac_zero_free(struct lc_kmac_ctx *kmac_ctx);
178
185static inline void lc_kmac_zero(struct lc_kmac_ctx *kmac_ctx)
186{
187 struct lc_hash_ctx *hash_ctx;
188 const struct lc_hash *hash;
189
190 if (!kmac_ctx)
191 return;
192 hash_ctx = &kmac_ctx->hash_ctx;
193 hash = hash_ctx->hash;
194
195 kmac_ctx->final_called = 0;
196 kmac_ctx->rng_initialized = 0;
197
198 lc_memset_secure((uint8_t *)kmac_ctx + sizeof(struct lc_kmac_ctx), 0,
199 kmac_ctx->shadow_ctx ?
200 LC_KMAC_STATE_SIZE_REINIT(hash) :
201 LC_KMAC_STATE_SIZE(hash));
202}
203
214#define LC_KMAC_CTX_ON_STACK(name, hashname) \
215 _Pragma("GCC diagnostic push") \
216 _Pragma("GCC diagnostic ignored \"-Wvla\"") _Pragma( \
217 "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
218 LC_ALIGNED_BUFFER(name##_ctx_buf, \
219 LC_KMAC_CTX_SIZE(hashname), \
220 LC_HASH_COMMON_ALIGNMENT); \
221 struct lc_kmac_ctx *name = (struct lc_kmac_ctx *)name##_ctx_buf; \
222 LC_KMAC_SET_CTX(name, hashname); \
223 lc_kmac_zero(name); \
224 _Pragma("GCC diagnostic pop")
225
237#define LC_KMAC_CTX_ON_STACK_REINIT(name, hashname) \
238 _Pragma("GCC diagnostic push") \
239 _Pragma("GCC diagnostic ignored \"-Wvla\"") _Pragma( \
240 "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
241 LC_ALIGNED_BUFFER(name##_ctx_buf, \
242 LC_KMAC_CTX_SIZE_REINIT(hashname), \
243 LC_HASH_COMMON_ALIGNMENT); \
244 struct lc_kmac_ctx *name = (struct lc_kmac_ctx *)name##_ctx_buf; \
245 LC_KMAC_SET_CTX_REINIT(name, hashname); \
246 lc_kmac_zero(name); \
247 _Pragma("GCC diagnostic pop")
248
256static inline size_t lc_kmac_macsize(struct lc_kmac_ctx *kmac_ctx)
257{
258 struct lc_hash_ctx *hash_ctx;
259
260 if (!kmac_ctx)
261 return 0;
262
263 hash_ctx = &kmac_ctx->hash_ctx;
264 return lc_hash_digestsize(hash_ctx);
265}
266
283static inline void lc_kmac(const struct lc_hash *hash, const uint8_t *key,
284 size_t keylen, const uint8_t *s, size_t slen,
285 const uint8_t *in, size_t inlen, uint8_t *mac,
286 size_t maclen)
287{
288 LC_KMAC_CTX_ON_STACK(kmac_ctx, hash);
289
290 lc_kmac_init(kmac_ctx, key, keylen, s, slen);
291 lc_kmac_update(kmac_ctx, in, inlen);
292 lc_kmac_final(kmac_ctx, mac, maclen);
293
294 lc_kmac_zero(kmac_ctx);
295}
296
313static inline void lc_kmac_xof(const struct lc_hash *hash, const uint8_t *key,
314 size_t keylen, const uint8_t *s, size_t slen,
315 const uint8_t *in, size_t inlen, uint8_t *mac,
316 size_t maclen)
317{
318 LC_KMAC_CTX_ON_STACK(kmac_ctx, hash);
319
320 lc_kmac_init(kmac_ctx, key, keylen, s, slen);
321 lc_kmac_update(kmac_ctx, in, inlen);
322 lc_kmac_final_xof(kmac_ctx, mac, maclen);
323
324 lc_kmac_zero(kmac_ctx);
325}
326
327/******************************** KMAC as RNG *********************************/
328
329/*
330 * The KMAC can be used as an RNG context for aggregated algorithms like
331 * Kyber or Dilithium. The idea is that KMAC acts as a key derivation function
332 * whose state can be initialized from an input data to deterministically derive
333 * the values required for the algorithms the RNG context is used with.
334 *
335 * This RNG state is NOT intended to serve as a general-purpose deterministic
336 * random number generator. For using KMAC as a such general-purpose DRNG, see
337 * the API provided with lc_kmac256_drng.h.
338 */
339
340/* KMAC DRNG implementation */
341extern const struct lc_rng *lc_kmac_rng;
342
343#define LC_KMAC_KDF_DRNG_CTX_SIZE(hashname) \
344 (sizeof(struct lc_rng_ctx) + LC_KMAC_CTX_SIZE(hashname))
345
346#define LC_KMAC_KDF_DRNG_SET_CTX(name, hashname) LC_KMAC_SET_CTX(name, hashname)
347
348#define LC_KMAC_KDF_RNG_CTX(name, hashname) \
349 LC_RNG_CTX(name, lc_kmac_rng); \
350 LC_KMAC_KDF_DRNG_SET_CTX(((struct lc_kmac_ctx *)(name->rng_state)), \
351 hashname); \
352 lc_rng_zero(name)
353
361#define LC_KMAC_KDF_DRNG_CTX_ON_STACK(name, hashname) \
362 _Pragma("GCC diagnostic push") \
363 _Pragma("GCC diagnostic ignored \"-Wvla\"") _Pragma( \
364 "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
365 LC_ALIGNED_BUFFER(name##_ctx_buf, \
366 LC_KMAC_KDF_DRNG_CTX_SIZE(hashname), \
367 LC_HASH_COMMON_ALIGNMENT); \
368 struct lc_rng_ctx *name = (struct lc_rng_ctx *)name##_ctx_buf; \
369 LC_KMAC_KDF_RNG_CTX(name, hashname); \
370 _Pragma("GCC diagnostic pop")
371
387int lc_kmac_rng_alloc(struct lc_rng_ctx **state, const struct lc_hash *hash);
388
389#ifdef __cplusplus
390}
391#endif
392
393#endif /* LC_KMAC_H */
static size_t lc_hash_digestsize(struct lc_hash_ctx *hash_ctx)
Get the size of the message digest.
Definition lc_hash.h:231
void lc_hash(const struct lc_hash *hash, const uint8_t *in, size_t inlen, uint8_t *digest)
Calculate message digest - one-shot.
const struct lc_rng * lc_kmac_rng
void lc_kmac_final(struct lc_kmac_ctx *kmac_ctx, uint8_t *mac, size_t maclen)
Calculate KMAC MAC.
#define LC_KMAC_CTX_ON_STACK(name, hashname)
Allocate stack memory for the KMAC context.
Definition lc_kmac.h:214
int lc_kmac_alloc(const struct lc_hash *hash, struct lc_kmac_ctx **kmac_ctx, uint32_t flags)
Allocate KMAC context on heap.
static void lc_kmac_zero(struct lc_kmac_ctx *kmac_ctx)
Zeroize KMAC context allocated with either LC_KMAC_CTX_ON_STACK or lc_kmac_alloc.
Definition lc_kmac.h:185
static size_t lc_kmac_macsize(struct lc_kmac_ctx *kmac_ctx)
Return the MAC size.
Definition lc_kmac.h:256
static void lc_kmac(const struct lc_hash *hash, const uint8_t *key, size_t keylen, const uint8_t *s, size_t slen, const uint8_t *in, size_t inlen, uint8_t *mac, size_t maclen)
Calculate KMAC - one-shot.
Definition lc_kmac.h:283
void lc_kmac_final_xof(struct lc_kmac_ctx *kmac_ctx, uint8_t *mac, size_t maclen)
Calculate KMAC MAC in XOF mode.
void lc_kmac_update(struct lc_kmac_ctx *kmac_ctx, const uint8_t *in, size_t inlen)
Update KMAC.
static void lc_kmac_xof(const struct lc_hash *hash, const uint8_t *key, size_t keylen, const uint8_t *s, size_t slen, const uint8_t *in, size_t inlen, uint8_t *mac, size_t maclen)
Calculate KMAC in XOF mode - one-shot.
Definition lc_kmac.h:313
int lc_kmac_rng_alloc(struct lc_rng_ctx **state, const struct lc_hash *hash)
Allocation of a KMAC DRNG context.
void lc_kmac_zero_free(struct lc_kmac_ctx *kmac_ctx)
Zeroize and free KMAC context.
void lc_kmac_init(struct lc_kmac_ctx *kmac_ctx, const uint8_t *key, size_t klen, const uint8_t *s, size_t slen)
Initialize KMAC context.
void lc_kmac_reinit(struct lc_kmac_ctx *kmac_ctx)
Re-initialize KMAC context after a kmac_final operation.
static void lc_memset_secure(void *s, int c, size_t n)