From 967c430481a44bfc4a08f74f7bd15877c30a5d54 Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Wed, 6 May 2026 16:11:45 +0200 Subject: [PATCH 1/2] KMAC - NIST SP 800-185 --- doc/crypt.tex | 106 +++++++++++++++++++ src/hashes/sha3.c | 7 ++ src/headers/tomcrypt_custom.h | 5 + src/headers/tomcrypt_mac.h | 36 +++++++ src/headers/tomcrypt_private.h | 4 + src/mac/kmac/kmac.c | 171 +++++++++++++++++++++++++++++++ src/mac/kmac/kmac_file.c | 90 ++++++++++++++++ src/mac/kmac/kmac_memory.c | 47 +++++++++ src/mac/kmac/kmac_memory_multi.c | 60 +++++++++++ src/mac/kmac/kmac_test.c | 123 ++++++++++++++++++++++ src/misc/crypt/crypt.c | 3 + tests/mac_test.c | 3 + 12 files changed, 655 insertions(+) create mode 100644 src/mac/kmac/kmac.c create mode 100644 src/mac/kmac/kmac_file.c create mode 100644 src/mac/kmac/kmac_memory.c create mode 100644 src/mac/kmac/kmac_memory_multi.c create mode 100644 src/mac/kmac/kmac_test.c diff --git a/doc/crypt.tex b/doc/crypt.tex index 982103389..256fdfbd6 100644 --- a/doc/crypt.tex +++ b/doc/crypt.tex @@ -3980,6 +3980,112 @@ \subsection{F9--MAC Functions} Which will BLAKE2s/b--MAC the entire contents of the file specified by \textit{fname} using the key \textit{key} of length \textit{keylen} bytes. It will store the MAC in \textit{mac} with the same rules as blake2smac\_done(). +\mysection{KMAC} + +KMAC is a keyed message authentication code based on the Keccak permutation, standardised by NIST in +SP 800--185. The library provides KMAC128 and KMAC256, each available in fixed--length and +extendable--output (XOF) variants. + +The desired flavour is selected through the \textit{variant} argument, which must be exactly one of the +following four named constants: + +\begin{center} +\begin{tabular}{ll} +\hline +\textit{variant} & resulting algorithm \\ +\hline +\texttt{LTC\_KMAC128} & KMAC128 \\ +\texttt{LTC\_KMAC256} & KMAC256 \\ +\texttt{LTC\_KMAC128\_XOF} & KMACXOF128 \\ +\texttt{LTC\_KMAC256\_XOF} & KMACXOF256 \\ +\hline +\end{tabular} +\end{center} + +Any other value passed in \textit{variant} causes the init function to return \textbf{CRYPT\_INVALID\_ARG}. + +A KMAC state is initialised with the following function: +\index{kmac\_init()} +\begin{verbatim} +int kmac_init( kmac_state *st, + int variant, + const unsigned char *key, + unsigned long keylen, + const unsigned char *cust, + unsigned long custlen); +\end{verbatim} +This will initialise the KMAC state \textit{st} with the key in \textit{key} of length \textit{keylen} octets +and the optional customisation string in \textit{cust} of length \textit{custlen} octets. The customisation +string may be empty: pass \textbf{NULL} as \textit{cust} together with \textit{custlen} equal to zero. + +To process data through KMAC use the following function: +\index{kmac\_process()} +\begin{verbatim} +int kmac_process( kmac_state *st, + const unsigned char *in, + unsigned long inlen); +\end{verbatim} +This will add the message octets pointed to by \textit{in} of length \textit{inlen} to the KMAC state pointed +to by \textit{st}. + +To compute the MAC tag use: +\index{kmac\_done()} +\begin{verbatim} +int kmac_done( kmac_state *st, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} +On entry \textit{outlen} holds the requested output size in octets; on exit it holds the number of octets +actually written to \textit{out}. For the fixed--length variants the requested length is bound into the +authentication tag, so callers must commit to it before calling kmac\_done(). For the XOF variants the +requested length is independent of the tag computation and any output length may be asked for. + +Helper functions are provided to make hashing memory buffers and files easier: +\index{kmac\_memory()} +\begin{verbatim} +int kmac_memory( int variant, + const unsigned char *key, + unsigned long keylen, + const unsigned char *cust, + unsigned long custlen, + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} +This will compute the KMAC of \textit{inlen} bytes of \textit{in} using the key \textit{key} of length +\textit{keylen} bytes and the customisation string \textit{cust} of length \textit{custlen} bytes. The result +is stored in \textit{out} following the same rules as kmac\_done(). + +\index{kmac\_memory\_multi()} +\begin{verbatim} +int kmac_memory_multi( int variant, + const unsigned char *key, + unsigned long keylen, + const unsigned char *cust, + unsigned long custlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *in, + unsigned long inlen, ...); +\end{verbatim} +The variadic form accepts an arbitrary number of (data, length) pairs, terminated by a \textbf{NULL} pointer. + +To KMAC a file use: +\index{kmac\_file()} +\begin{verbatim} +int kmac_file( int variant, + const unsigned char *key, + unsigned long keylen, + const unsigned char *cust, + unsigned long custlen, + const char *fname, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} +Which will KMAC the entire contents of the file named \textit{fname} and store the tag in \textit{out} +following the same rules as kmac\_done(). + \chapter{Pseudo-Random Number Generators} \mysection{Core Functions} The library provides an array of core functions for Pseudo-Random Number Generators (PRNGs) as well. A cryptographic PRNG is diff --git a/src/hashes/sha3.c b/src/hashes/sha3.c index 37373fb68..07965f404 100644 --- a/src/hashes/sha3.c +++ b/src/hashes/sha3.c @@ -446,6 +446,13 @@ int sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen) return s_sha3_shake_done(&md->sha3, out, outlen, 0x1f, s_keccakf); } +#ifdef LTC_KMAC +int sha3_shake_done_ex(hash_state *md, unsigned char *out, unsigned long outlen, unsigned char domain) +{ + return s_sha3_shake_done(&md->sha3, out, outlen, domain, s_keccakf); +} +#endif + int sha3_shake128_done(hash_state *md, unsigned char *out) { return sha3_shake_done(md, out, 32); diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 75e738fc9..20d0586a1 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -300,6 +300,7 @@ #define LTC_POLY1305 #define LTC_BLAKE2SMAC #define LTC_BLAKE2BMAC +#define LTC_KMAC /* ---> Encrypt + Authenticate Modes <--- */ @@ -734,6 +735,10 @@ #error LTC_BLAKE2BMAC requires LTC_BLAKE2B #endif +#if defined(LTC_KMAC) && !defined(LTC_SHA3) + #error LTC_KMAC requires LTC_SHA3 +#endif + #if defined(LTC_SPRNG) && !defined(LTC_RNG_GET_BYTES) #error LTC_SPRNG requires LTC_RNG_GET_BYTES #endif diff --git a/src/headers/tomcrypt_mac.h b/src/headers/tomcrypt_mac.h index 039600137..49cc1ccd8 100644 --- a/src/headers/tomcrypt_mac.h +++ b/src/headers/tomcrypt_mac.h @@ -135,6 +135,42 @@ int blake2smac_file(const char *fname, const unsigned char *key, unsigned long k int blake2smac_test(void); #endif /* LTC_BLAKE2SMAC */ +#ifdef LTC_KMAC +/* values for the `variant` argument of kmac_init() and friends */ +#define LTC_KMAC128 1 +#define LTC_KMAC256 2 +#define LTC_KMAC128_XOF 3 +#define LTC_KMAC256_XOF 4 + +typedef struct Kmac_state { + hash_state sha3; + int xof; +} kmac_state; + +int kmac_init(kmac_state *st, int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen); +int kmac_process(kmac_state *st, const unsigned char *in, unsigned long inlen); +int kmac_done(kmac_state *st, unsigned char *out, unsigned long *outlen); +int kmac_memory(int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); +int kmac_memory_multi(int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen, + unsigned char *out, unsigned long *outlen, + const unsigned char *in, unsigned long inlen, ...) + LTC_NULL_TERMINATED; +int kmac_file(int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen, + const char *fname, + unsigned char *out, unsigned long *outlen); +int kmac_test(void); +#endif /* LTC_KMAC */ + #ifdef LTC_BLAKE2BMAC typedef hash_state blake2bmac_state; int blake2bmac_init(blake2bmac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen); diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 6df57ef9f..a823e9b4e 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -197,6 +197,10 @@ int sha224_test_desc(const struct ltc_hash_descriptor *desc, const char *name); int sha256_test_desc(const struct ltc_hash_descriptor *desc, const char *name); #endif +#ifdef LTC_KMAC +int sha3_shake_done_ex(hash_state *md, unsigned char *out, unsigned long outlen, unsigned char domain); +#endif + /* tomcrypt_mac.h */ int ocb3_int_ntz(unsigned long x); diff --git a/src/mac/kmac/kmac.c b/src/mac/kmac/kmac.c new file mode 100644 index 000000000..1a0af38ea --- /dev/null +++ b/src/mac/kmac/kmac.c @@ -0,0 +1,171 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include "tomcrypt_private.h" + +/** + @file kmac.c + KMAC as defined in NIST SP 800-185 +*/ + +#ifdef LTC_KMAC + +/* Encoding helpers from NIST SP 800-185 2.3 - encoded output never exceeds 9 bytes (8 byte payload + 1 length byte) */ +static unsigned long s_left_encode(ulong64 x, unsigned char *out) +{ + int i, n = 1; + for (i = 7; i > 0; --i) { + if ((x >> (i * 8)) & 0xff) { + n = i + 1; + break; + } + } + out[0] = (unsigned char)n; + for (i = 0; i < n; ++i) { + out[1 + i] = (unsigned char)(x >> ((n - 1 - i) * 8)); + } + return (unsigned long)(n + 1); +} + +static unsigned long s_right_encode(ulong64 x, unsigned char *out) +{ + int i, n = 1; + for (i = 7; i > 0; --i) { + if ((x >> (i * 8)) & 0xff) { + n = i + 1; + break; + } + } + for (i = 0; i < n; ++i) { + out[i] = (unsigned char)(x >> ((n - 1 - i) * 8)); + } + out[n] = (unsigned char)n; + return (unsigned long)(n + 1); +} + +static int s_feed_encode_string(hash_state *md, const unsigned char *s, unsigned long slen, unsigned long *total) +{ + unsigned char enc[9]; + unsigned long enclen; + int err; + enclen = s_left_encode((ulong64)slen * 8, enc); + if ((err = sha3_process(md, enc, enclen)) != CRYPT_OK) return err; + *total += enclen; + if (slen != 0) { + if ((err = sha3_process(md, s, slen)) != CRYPT_OK) return err; + *total += slen; + } + return CRYPT_OK; +} + +static int s_feed_bytepad_zero_fill(hash_state *md, unsigned long rate, unsigned long total) +{ + unsigned long pad = (rate - (total % rate)) % rate; + if (pad != 0) { + unsigned char zeros[168]; /* >= max SHAKE rate */ + XMEMSET(zeros, 0, sizeof(zeros)); + return sha3_process(md, zeros, pad); + } + return CRYPT_OK; +} + +static int s_feed_bytepad_prefix(hash_state *md, unsigned long rate, unsigned long *total) +{ + unsigned char enc[9]; + unsigned long enclen = s_left_encode(rate, enc); + int err = sha3_process(md, enc, enclen); + if (err == CRYPT_OK) *total = enclen; + return err; +} + +/** + Initialize a KMAC context + + @param st The KMAC state + @param variant one of LTC_KMAC128, LTC_KMAC256, LTC_KMAC128_XOF, LTC_KMAC256_XOF + @param key The secret key + @param keylen The length of the secret key (octets) + @param cust Optional customization string (may be NULL when custlen == 0) + @param custlen Length of the customization string (octets) + @return CRYPT_OK if successful +*/ +int kmac_init(kmac_state *st, int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen) +{ + static const unsigned char kmac_name[4] = { 'K', 'M', 'A', 'C' }; + int err, num; + unsigned long rate, total; + + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(key != NULL || keylen == 0); + LTC_ARGCHK(cust != NULL || custlen == 0); + + switch (variant) { + case LTC_KMAC128: num = 128; st->xof = 0; rate = 168; break; + case LTC_KMAC256: num = 256; st->xof = 0; rate = 136; break; + case LTC_KMAC128_XOF: num = 128; st->xof = 1; rate = 168; break; + case LTC_KMAC256_XOF: num = 256; st->xof = 1; rate = 136; break; + default: return CRYPT_INVALID_ARG; + } + + if ((err = sha3_shake_init(&st->sha3, num)) != CRYPT_OK) return err; + + /* bytepad(encode_string("KMAC") || encode_string(cust), rate) */ + if ((err = s_feed_bytepad_prefix(&st->sha3, rate, &total)) != CRYPT_OK) return err; + if ((err = s_feed_encode_string(&st->sha3, kmac_name, sizeof(kmac_name), &total)) != CRYPT_OK) return err; + if ((err = s_feed_encode_string(&st->sha3, cust, custlen, &total)) != CRYPT_OK) return err; + if ((err = s_feed_bytepad_zero_fill(&st->sha3, rate, total)) != CRYPT_OK) return err; + + /* bytepad(encode_string(key), rate) */ + if ((err = s_feed_bytepad_prefix(&st->sha3, rate, &total)) != CRYPT_OK) return err; + if ((err = s_feed_encode_string(&st->sha3, key, keylen, &total)) != CRYPT_OK) return err; + if ((err = s_feed_bytepad_zero_fill(&st->sha3, rate, total)) != CRYPT_OK) return err; + + return CRYPT_OK; +} + +/** + Process data through KMAC + + @param st The KMAC state + @param in The data to authenticate + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +int kmac_process(kmac_state *st, const unsigned char *in, unsigned long inlen) +{ + if (inlen == 0) return CRYPT_OK; + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(in != NULL); + return sha3_process(&st->sha3, in, inlen); +} + +/** + Terminate a KMAC session + + @param st The KMAC state + @param out [out] The destination of the MAC + @param outlen [in/out] The requested length on entry, the produced length on return + @return CRYPT_OK if successful +*/ +int kmac_done(kmac_state *st, unsigned char *out, unsigned long *outlen) +{ + unsigned char enc[9]; + unsigned long enclen; + int err; + ulong64 L; + + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + /* SP 800-185 4: append right_encode(L) where L is the requested output length in bits or right_encode(0) for the XOF flavour */ + L = st->xof ? 0 : (ulong64)(*outlen) * 8; + enclen = s_right_encode(L, enc); + if ((err = sha3_process(&st->sha3, enc, enclen)) != CRYPT_OK) return err; + + return sha3_shake_done_ex(&st->sha3, out, *outlen, 0x04); +} + +#endif diff --git a/src/mac/kmac/kmac_file.c b/src/mac/kmac/kmac_file.c new file mode 100644 index 000000000..c3cc1fafb --- /dev/null +++ b/src/mac/kmac/kmac_file.c @@ -0,0 +1,90 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include "tomcrypt_private.h" + +#ifdef LTC_KMAC + +/** + KMAC a file + + @param variant 128 or 256 (optionally OR-ed with LTC_KMAC_XOF) + @param key The secret key + @param keylen The length of the secret key (octets) + @param cust Optional customization string (may be NULL when custlen == 0) + @param custlen Length of the customization string (octets) + @param fname The name of the file you wish to MAC + @param out [out] Destination of the MAC + @param outlen [in/out] Requested length on entry, produced length on return + @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled +*/ +int kmac_file(int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen, + const char *fname, + unsigned char *out, unsigned long *outlen) +{ +#ifdef LTC_NO_FILE + LTC_UNUSED_PARAM(variant); + LTC_UNUSED_PARAM(key); + LTC_UNUSED_PARAM(keylen); + LTC_UNUSED_PARAM(cust); + LTC_UNUSED_PARAM(custlen); + LTC_UNUSED_PARAM(fname); + LTC_UNUSED_PARAM(out); + LTC_UNUSED_PARAM(outlen); + return CRYPT_NOP; +#else + kmac_state st; + FILE *in; + unsigned char *buf; + size_t x; + int err; + + LTC_ARGCHK(fname != NULL); + LTC_ARGCHK(key != NULL || keylen == 0); + LTC_ARGCHK(cust != NULL || custlen == 0); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) { + return CRYPT_MEM; + } + + if ((err = kmac_init(&st, variant, key, keylen, cust, custlen)) != CRYPT_OK) { + goto LBL_ERR; + } + + in = fopen(fname, "rb"); + if (in == NULL) { + err = CRYPT_FILE_NOTFOUND; + goto LBL_ERR; + } + + do { + x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in); + if ((err = kmac_process(&st, buf, (unsigned long)x)) != CRYPT_OK) { + fclose(in); + goto LBL_CLEANBUF; + } + } while (x == LTC_FILE_READ_BUFSIZE); + + if (fclose(in) != 0) { + err = CRYPT_ERROR; + goto LBL_CLEANBUF; + } + + err = kmac_done(&st, out, outlen); + +LBL_CLEANBUF: + zeromem(buf, LTC_FILE_READ_BUFSIZE); +LBL_ERR: +#ifdef LTC_CLEAN_STACK + zeromem(&st, sizeof(st)); +#endif + XFREE(buf); + return err; +#endif +} + +#endif diff --git a/src/mac/kmac/kmac_memory.c b/src/mac/kmac/kmac_memory.c new file mode 100644 index 000000000..0b950460f --- /dev/null +++ b/src/mac/kmac/kmac_memory.c @@ -0,0 +1,47 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include "tomcrypt_private.h" + +#ifdef LTC_KMAC + +/** + KMAC a block of memory to produce the authentication tag + + @param variant 128 or 256 (optionally OR-ed with LTC_KMAC_XOF) + @param key The secret key + @param keylen The length of the secret key (octets) + @param cust Optional customization string (may be NULL when custlen == 0) + @param custlen Length of the customization string (octets) + @param in The data to authenticate + @param inlen The length of the data (octets) + @param out [out] Destination of the MAC + @param outlen [in/out] Requested length on entry, produced length on return + @return CRYPT_OK if successful +*/ +int kmac_memory(int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + kmac_state st; + int err; + + LTC_ARGCHK(key != NULL || keylen == 0); + LTC_ARGCHK(cust != NULL || custlen == 0); + LTC_ARGCHK(in != NULL || inlen == 0); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + if ((err = kmac_init(&st, variant, key, keylen, cust, custlen)) != CRYPT_OK) goto LBL_ERR; + if ((err = kmac_process(&st, in, inlen)) != CRYPT_OK) goto LBL_ERR; + err = kmac_done(&st, out, outlen); +LBL_ERR: +#ifdef LTC_CLEAN_STACK + zeromem(&st, sizeof(st)); +#endif + return err; +} + +#endif diff --git a/src/mac/kmac/kmac_memory_multi.c b/src/mac/kmac/kmac_memory_multi.c new file mode 100644 index 000000000..f5ba283c4 --- /dev/null +++ b/src/mac/kmac/kmac_memory_multi.c @@ -0,0 +1,60 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include "tomcrypt_private.h" + +#ifdef LTC_KMAC + +/** + KMAC multiple blocks of memory to produce the authentication tag + + @param variant 128 or 256 (optionally OR-ed with LTC_KMAC_XOF) + @param key The secret key + @param keylen The length of the secret key (octets) + @param cust Optional customization string (may be NULL when custlen == 0) + @param custlen Length of the customization string (octets) + @param out [out] Destination of the MAC + @param outlen [in/out] Requested length on entry, produced length on return + @param in The data to authenticate + @param inlen The length of the data (octets) + @param ... tuples of (data, len) pairs to authenticate, terminated with (NULL, x) + @return CRYPT_OK if successful +*/ +int kmac_memory_multi(int variant, + const unsigned char *key, unsigned long keylen, + const unsigned char *cust, unsigned long custlen, + unsigned char *out, unsigned long *outlen, + const unsigned char *in, unsigned long inlen, ...) +{ + kmac_state st; + int err; + va_list args; + const unsigned char *curptr; + unsigned long curlen; + + LTC_ARGCHK(key != NULL || keylen == 0); + LTC_ARGCHK(cust != NULL || custlen == 0); + LTC_ARGCHK(in != NULL || inlen == 0); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + va_start(args, inlen); + curptr = in; + curlen = inlen; + if ((err = kmac_init(&st, variant, key, keylen, cust, custlen)) != CRYPT_OK) goto LBL_ERR; + for (;;) { + if ((err = kmac_process(&st, curptr, curlen)) != CRYPT_OK) goto LBL_ERR; + curptr = va_arg(args, const unsigned char*); + if (curptr == NULL) break; + curlen = va_arg(args, unsigned long); + } + err = kmac_done(&st, out, outlen); +LBL_ERR: +#ifdef LTC_CLEAN_STACK + zeromem(&st, sizeof(st)); +#endif + va_end(args); + return err; +} + +#endif diff --git a/src/mac/kmac/kmac_test.c b/src/mac/kmac/kmac_test.c new file mode 100644 index 000000000..cf8a003df --- /dev/null +++ b/src/mac/kmac/kmac_test.c @@ -0,0 +1,123 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include "tomcrypt_private.h" + +#ifdef LTC_KMAC + +/* Test vectors from NIST SP 800-185 sample document (KMAC_samples.pdf) */ +int kmac_test(void) +{ +#ifndef LTC_TEST + return CRYPT_NOP; +#else + static const unsigned char key[32] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F + }; + static const unsigned char data4[4] = { 0x00, 0x01, 0x02, 0x03 }; + static unsigned char data200[200]; + static const char tag_app[] = "My Tagged Application"; + + static const struct { + int variant; + unsigned long custlen; + unsigned long inlen; + unsigned long outlen; + const unsigned char *in; + unsigned char out[64]; + } tests[] = { + /* sample #1: KMAC128, S="" */ + { LTC_KMAC128, 0, 4, 32, data4, { + 0xE5, 0x78, 0x0B, 0x0D, 0x3E, 0xA6, 0xF7, 0xD3, 0xA4, 0x29, 0xC5, 0x70, 0x6A, 0xA4, 0x3A, 0x00, + 0xFA, 0xDB, 0xD7, 0xD4, 0x96, 0x28, 0x83, 0x9E, 0x31, 0x87, 0x24, 0x3F, 0x45, 0x6E, 0xE1, 0x4E } }, + /* sample #2: KMAC128, S="My Tagged Application" */ + { LTC_KMAC128, 21, 4, 32, data4, { + 0x3B, 0x1F, 0xBA, 0x96, 0x3C, 0xD8, 0xB0, 0xB5, 0x9E, 0x8C, 0x1A, 0x6D, 0x71, 0x88, 0x8B, 0x71, + 0x43, 0x65, 0x1A, 0xF8, 0xBA, 0x0A, 0x70, 0x70, 0xC0, 0x97, 0x9E, 0x28, 0x11, 0x32, 0x4A, 0xA5 } }, + /* sample #3: KMAC128, 200-byte input, S="My Tagged Application" */ + { LTC_KMAC128, 21, 200, 32, data200, { + 0x1F, 0x5B, 0x4E, 0x6C, 0xCA, 0x02, 0x20, 0x9E, 0x0D, 0xCB, 0x5C, 0xA6, 0x35, 0xB8, 0x9A, 0x15, + 0xE2, 0x71, 0xEC, 0xC7, 0x60, 0x07, 0x1D, 0xFD, 0x80, 0x5F, 0xAA, 0x38, 0xF9, 0x72, 0x92, 0x30 } }, + /* sample #4: KMAC256, S="My Tagged Application" */ + { LTC_KMAC256, 21, 4, 64, data4, { + 0x20, 0xC5, 0x70, 0xC3, 0x13, 0x46, 0xF7, 0x03, 0xC9, 0xAC, 0x36, 0xC6, 0x1C, 0x03, 0xCB, 0x64, + 0xC3, 0x97, 0x0D, 0x0C, 0xFC, 0x78, 0x7E, 0x9B, 0x79, 0x59, 0x9D, 0x27, 0x3A, 0x68, 0xD2, 0xF7, + 0xF6, 0x9D, 0x4C, 0xC3, 0xDE, 0x9D, 0x10, 0x4A, 0x35, 0x16, 0x89, 0xF2, 0x7C, 0xF6, 0xF5, 0x95, + 0x1F, 0x01, 0x03, 0xF3, 0x3F, 0x4F, 0x24, 0x87, 0x10, 0x24, 0xD9, 0xC2, 0x77, 0x73, 0xA8, 0xDD } }, + /* sample #5: KMAC256, 200-byte input, S="" */ + { LTC_KMAC256, 0, 200, 64, data200, { + 0x75, 0x35, 0x8C, 0xF3, 0x9E, 0x41, 0x49, 0x4E, 0x94, 0x97, 0x07, 0x92, 0x7C, 0xEE, 0x0A, 0xF2, + 0x0A, 0x3F, 0xF5, 0x53, 0x90, 0x4C, 0x86, 0xB0, 0x8F, 0x21, 0xCC, 0x41, 0x4B, 0xCF, 0xD6, 0x91, + 0x58, 0x9D, 0x27, 0xCF, 0x5E, 0x15, 0x36, 0x9C, 0xBB, 0xFF, 0x8B, 0x9A, 0x4C, 0x2E, 0xB1, 0x78, + 0x00, 0x85, 0x5D, 0x02, 0x35, 0xFF, 0x63, 0x5D, 0xA8, 0x25, 0x33, 0xEC, 0x6B, 0x75, 0x9B, 0x69 } }, + /* sample #7: KMACXOF128, S="" */ + { LTC_KMAC128_XOF, 0, 4, 32, data4, { + 0xCD, 0x83, 0x74, 0x0B, 0xBD, 0x92, 0xCC, 0xC8, 0xCF, 0x03, 0x2B, 0x14, 0x81, 0xA0, 0xF4, 0x46, + 0x0E, 0x7C, 0xA9, 0xDD, 0x12, 0xB0, 0x8A, 0x0C, 0x40, 0x31, 0x17, 0x8B, 0xAC, 0xD6, 0xEC, 0x35 } }, + /* sample #8: KMACXOF128, S="My Tagged Application" */ + { LTC_KMAC128_XOF, 21, 4, 32, data4, { + 0x31, 0xA4, 0x45, 0x27, 0xB4, 0xED, 0x9F, 0x5C, 0x61, 0x01, 0xD1, 0x1D, 0xE6, 0xD2, 0x6F, 0x06, + 0x20, 0xAA, 0x5C, 0x34, 0x1D, 0xEF, 0x41, 0x29, 0x96, 0x57, 0xFE, 0x9D, 0xF1, 0xA3, 0xB1, 0x6C } }, + /* sample #9: KMACXOF128, 200-byte input, S="My Tagged Application" */ + { LTC_KMAC128_XOF, 21, 200, 32, data200, { + 0x47, 0x02, 0x6C, 0x7C, 0xD7, 0x93, 0x08, 0x4A, 0xA0, 0x28, 0x3C, 0x25, 0x3E, 0xF6, 0x58, 0x49, + 0x0C, 0x0D, 0xB6, 0x14, 0x38, 0xB8, 0x32, 0x6F, 0xE9, 0xBD, 0xDF, 0x28, 0x1B, 0x83, 0xAE, 0x0F } }, + /* sample #10: KMACXOF256, S="My Tagged Application" */ + { LTC_KMAC256_XOF, 21, 4, 64, data4, { + 0x17, 0x55, 0x13, 0x3F, 0x15, 0x34, 0x75, 0x2A, 0xAD, 0x07, 0x48, 0xF2, 0xC7, 0x06, 0xFB, 0x5C, + 0x78, 0x45, 0x12, 0xCA, 0xB8, 0x35, 0xCD, 0x15, 0x67, 0x6B, 0x16, 0xC0, 0xC6, 0x64, 0x7F, 0xA9, + 0x6F, 0xAA, 0x7A, 0xF6, 0x34, 0xA0, 0xBF, 0x8F, 0xF6, 0xDF, 0x39, 0x37, 0x4F, 0xA0, 0x0F, 0xAD, + 0x9A, 0x39, 0xE3, 0x22, 0xA7, 0xC9, 0x20, 0x65, 0xA6, 0x4E, 0xB1, 0xFB, 0x08, 0x01, 0xEB, 0x2B } }, + /* sample #11: KMACXOF256, 200-byte input, S="" */ + { LTC_KMAC256_XOF, 0, 200, 64, data200, { + 0xFF, 0x7B, 0x17, 0x1F, 0x1E, 0x8A, 0x2B, 0x24, 0x68, 0x3E, 0xED, 0x37, 0x83, 0x0E, 0xE7, 0x97, + 0x53, 0x8B, 0xA8, 0xDC, 0x56, 0x3F, 0x6D, 0xA1, 0xE6, 0x67, 0x39, 0x1A, 0x75, 0xED, 0xC0, 0x2C, + 0xA6, 0x33, 0x07, 0x9F, 0x81, 0xCE, 0x12, 0xA2, 0x5F, 0x45, 0x61, 0x5E, 0xC8, 0x99, 0x72, 0x03, + 0x1D, 0x18, 0x33, 0x73, 0x31, 0xD2, 0x4C, 0xEB, 0x8F, 0x8C, 0xA8, 0xE6, 0xA1, 0x9F, 0xD9, 0x8B } } + }; + unsigned int i; + unsigned char buf[64]; + unsigned long buflen; + int err; + + for (i = 0; i < sizeof(data200); ++i) data200[i] = (unsigned char)i; + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) { + const unsigned char *cust = (tests[i].custlen == 0) ? NULL : (const unsigned char*)tag_app; + buflen = tests[i].outlen; + if ((err = kmac_memory(tests[i].variant, key, sizeof(key), cust, tests[i].custlen, + tests[i].in, tests[i].inlen, buf, &buflen)) != CRYPT_OK) return err; + if (ltc_compare_testvector(buf, buflen, tests[i].out, tests[i].outlen, "kmac", (int)i) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + + /* sample #6: KMAC256, 200-byte input, S="My Tagged Application", processed one byte at a time */ + { + static const unsigned char sample6[64] = { + 0xB5, 0x86, 0x18, 0xF7, 0x1F, 0x92, 0xE1, 0xD5, 0x6C, 0x1B, 0x8C, 0x55, 0xDD, 0xD7, 0xCD, 0x18, + 0x8B, 0x97, 0xB4, 0xCA, 0x4D, 0x99, 0x83, 0x1E, 0xB2, 0x69, 0x9A, 0x83, 0x7D, 0xA2, 0xE4, 0xD9, + 0x70, 0xFB, 0xAC, 0xFD, 0xE5, 0x00, 0x33, 0xAE, 0xA5, 0x85, 0xF1, 0xA2, 0x70, 0x85, 0x10, 0xC3, + 0x2D, 0x07, 0x88, 0x08, 0x01, 0xBD, 0x18, 0x28, 0x98, 0xFE, 0x47, 0x68, 0x76, 0xFC, 0x89, 0x65 + }; + kmac_state st; + unsigned int j; + if ((err = kmac_init(&st, LTC_KMAC256, key, sizeof(key), (const unsigned char*)tag_app, 21)) != CRYPT_OK) return err; + for (j = 0; j < sizeof(data200); ++j) { + if ((err = kmac_process(&st, &data200[j], 1)) != CRYPT_OK) return err; + } + buflen = 64; + if ((err = kmac_done(&st, buf, &buflen)) != CRYPT_OK) return err; + if (ltc_compare_testvector(buf, buflen, sample6, sizeof(sample6), "kmac stream", 0) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + + return CRYPT_OK; +#endif +} + +#endif diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index a670d69bb..0466e61d8 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -285,6 +285,9 @@ const char *crypt_build_settings = #if defined(LTC_BLAKE2BMAC) " BLAKE2B MAC\n" #endif +#if defined(LTC_KMAC) + " KMAC\n" +#endif "\nENC + AUTH modes:\n" #if defined(LTC_EAX_MODE) diff --git a/tests/mac_test.c b/tests/mac_test.c index d1c0307c6..1bb6f2cff 100644 --- a/tests/mac_test.c +++ b/tests/mac_test.c @@ -47,6 +47,9 @@ int mac_test(void) #ifdef LTC_BLAKE2BMAC DO(blake2bmac_test()); #endif +#ifdef LTC_KMAC + DO(kmac_test()); +#endif #ifdef LTC_SIV_MODE DO(siv_test()); DO(siv_wycheproof_test()); From be8c5de4a36f3dd4c1550fffc6b819d446460ae5 Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Wed, 6 May 2026 16:11:54 +0200 Subject: [PATCH 2/2] Update makefiles --- libtomcrypt_VS2008.vcproj | 24 ++++++++++++++++++++++++ makefile.mingw | 11 ++++++----- makefile.msvc | 11 ++++++----- makefile.unix | 11 ++++++----- makefile_include.mk | 11 ++++++----- sources.cmake | 5 +++++ 6 files changed, 53 insertions(+), 20 deletions(-) diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj index 11cfac1d5..5927eaadc 100644 --- a/libtomcrypt_VS2008.vcproj +++ b/libtomcrypt_VS2008.vcproj @@ -1155,6 +1155,30 @@ > + + + + + + + + + + + + diff --git a/makefile.mingw b/makefile.mingw index df39d6fbc..1552c4331 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -77,11 +77,12 @@ src/mac/blake2/blake2smac_memory_multi.o src/mac/blake2/blake2smac_test.o src/ma src/mac/f9/f9_file.o src/mac/f9/f9_init.o src/mac/f9/f9_memory.o src/mac/f9/f9_memory_multi.o \ src/mac/f9/f9_process.o src/mac/f9/f9_test.o src/mac/hmac/hmac_done.o src/mac/hmac/hmac_file.o \ src/mac/hmac/hmac_init.o src/mac/hmac/hmac_memory.o src/mac/hmac/hmac_memory_multi.o \ -src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o src/mac/omac/omac_done.o src/mac/omac/omac_file.o \ -src/mac/omac/omac_init.o src/mac/omac/omac_memory.o src/mac/omac/omac_memory_multi.o \ -src/mac/omac/omac_process.o src/mac/omac/omac_test.o src/mac/pelican/pelican.o \ -src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o src/mac/pmac/pmac_done.o \ -src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ +src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o src/mac/kmac/kmac.o src/mac/kmac/kmac_file.o \ +src/mac/kmac/kmac_memory.o src/mac/kmac/kmac_memory_multi.o src/mac/kmac/kmac_test.o \ +src/mac/omac/omac_done.o src/mac/omac/omac_file.o src/mac/omac/omac_init.o src/mac/omac/omac_memory.o \ +src/mac/omac/omac_memory_multi.o src/mac/omac/omac_process.o src/mac/omac/omac_test.o \ +src/mac/pelican/pelican.o src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o \ +src/mac/pmac/pmac_done.o src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ src/mac/pmac/pmac_memory_multi.o src/mac/pmac/pmac_ntz.o src/mac/pmac/pmac_process.o \ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/poly1305/poly1305.o \ src/mac/poly1305/poly1305_file.o src/mac/poly1305/poly1305_memory.o \ diff --git a/makefile.msvc b/makefile.msvc index e9028e8ab..c7bc53e27 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -70,11 +70,12 @@ src/mac/blake2/blake2smac_memory_multi.obj src/mac/blake2/blake2smac_test.obj sr src/mac/f9/f9_file.obj src/mac/f9/f9_init.obj src/mac/f9/f9_memory.obj src/mac/f9/f9_memory_multi.obj \ src/mac/f9/f9_process.obj src/mac/f9/f9_test.obj src/mac/hmac/hmac_done.obj src/mac/hmac/hmac_file.obj \ src/mac/hmac/hmac_init.obj src/mac/hmac/hmac_memory.obj src/mac/hmac/hmac_memory_multi.obj \ -src/mac/hmac/hmac_process.obj src/mac/hmac/hmac_test.obj src/mac/omac/omac_done.obj src/mac/omac/omac_file.obj \ -src/mac/omac/omac_init.obj src/mac/omac/omac_memory.obj src/mac/omac/omac_memory_multi.obj \ -src/mac/omac/omac_process.obj src/mac/omac/omac_test.obj src/mac/pelican/pelican.obj \ -src/mac/pelican/pelican_memory.obj src/mac/pelican/pelican_test.obj src/mac/pmac/pmac_done.obj \ -src/mac/pmac/pmac_file.obj src/mac/pmac/pmac_init.obj src/mac/pmac/pmac_memory.obj \ +src/mac/hmac/hmac_process.obj src/mac/hmac/hmac_test.obj src/mac/kmac/kmac.obj src/mac/kmac/kmac_file.obj \ +src/mac/kmac/kmac_memory.obj src/mac/kmac/kmac_memory_multi.obj src/mac/kmac/kmac_test.obj \ +src/mac/omac/omac_done.obj src/mac/omac/omac_file.obj src/mac/omac/omac_init.obj src/mac/omac/omac_memory.obj \ +src/mac/omac/omac_memory_multi.obj src/mac/omac/omac_process.obj src/mac/omac/omac_test.obj \ +src/mac/pelican/pelican.obj src/mac/pelican/pelican_memory.obj src/mac/pelican/pelican_test.obj \ +src/mac/pmac/pmac_done.obj src/mac/pmac/pmac_file.obj src/mac/pmac/pmac_init.obj src/mac/pmac/pmac_memory.obj \ src/mac/pmac/pmac_memory_multi.obj src/mac/pmac/pmac_ntz.obj src/mac/pmac/pmac_process.obj \ src/mac/pmac/pmac_shift_xor.obj src/mac/pmac/pmac_test.obj src/mac/poly1305/poly1305.obj \ src/mac/poly1305/poly1305_file.obj src/mac/poly1305/poly1305_memory.obj \ diff --git a/makefile.unix b/makefile.unix index b07b43b8c..1214ba9c9 100644 --- a/makefile.unix +++ b/makefile.unix @@ -91,11 +91,12 @@ src/mac/blake2/blake2smac_memory_multi.o src/mac/blake2/blake2smac_test.o src/ma src/mac/f9/f9_file.o src/mac/f9/f9_init.o src/mac/f9/f9_memory.o src/mac/f9/f9_memory_multi.o \ src/mac/f9/f9_process.o src/mac/f9/f9_test.o src/mac/hmac/hmac_done.o src/mac/hmac/hmac_file.o \ src/mac/hmac/hmac_init.o src/mac/hmac/hmac_memory.o src/mac/hmac/hmac_memory_multi.o \ -src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o src/mac/omac/omac_done.o src/mac/omac/omac_file.o \ -src/mac/omac/omac_init.o src/mac/omac/omac_memory.o src/mac/omac/omac_memory_multi.o \ -src/mac/omac/omac_process.o src/mac/omac/omac_test.o src/mac/pelican/pelican.o \ -src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o src/mac/pmac/pmac_done.o \ -src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ +src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o src/mac/kmac/kmac.o src/mac/kmac/kmac_file.o \ +src/mac/kmac/kmac_memory.o src/mac/kmac/kmac_memory_multi.o src/mac/kmac/kmac_test.o \ +src/mac/omac/omac_done.o src/mac/omac/omac_file.o src/mac/omac/omac_init.o src/mac/omac/omac_memory.o \ +src/mac/omac/omac_memory_multi.o src/mac/omac/omac_process.o src/mac/omac/omac_test.o \ +src/mac/pelican/pelican.o src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o \ +src/mac/pmac/pmac_done.o src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ src/mac/pmac/pmac_memory_multi.o src/mac/pmac/pmac_ntz.o src/mac/pmac/pmac_process.o \ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/poly1305/poly1305.o \ src/mac/poly1305/poly1305_file.o src/mac/poly1305/poly1305_memory.o \ diff --git a/makefile_include.mk b/makefile_include.mk index 0577b5bda..924e0b432 100644 --- a/makefile_include.mk +++ b/makefile_include.mk @@ -262,11 +262,12 @@ src/mac/blake2/blake2smac_memory_multi.o src/mac/blake2/blake2smac_test.o src/ma src/mac/f9/f9_file.o src/mac/f9/f9_init.o src/mac/f9/f9_memory.o src/mac/f9/f9_memory_multi.o \ src/mac/f9/f9_process.o src/mac/f9/f9_test.o src/mac/hmac/hmac_done.o src/mac/hmac/hmac_file.o \ src/mac/hmac/hmac_init.o src/mac/hmac/hmac_memory.o src/mac/hmac/hmac_memory_multi.o \ -src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o src/mac/omac/omac_done.o src/mac/omac/omac_file.o \ -src/mac/omac/omac_init.o src/mac/omac/omac_memory.o src/mac/omac/omac_memory_multi.o \ -src/mac/omac/omac_process.o src/mac/omac/omac_test.o src/mac/pelican/pelican.o \ -src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o src/mac/pmac/pmac_done.o \ -src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ +src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o src/mac/kmac/kmac.o src/mac/kmac/kmac_file.o \ +src/mac/kmac/kmac_memory.o src/mac/kmac/kmac_memory_multi.o src/mac/kmac/kmac_test.o \ +src/mac/omac/omac_done.o src/mac/omac/omac_file.o src/mac/omac/omac_init.o src/mac/omac/omac_memory.o \ +src/mac/omac/omac_memory_multi.o src/mac/omac/omac_process.o src/mac/omac/omac_test.o \ +src/mac/pelican/pelican.o src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o \ +src/mac/pmac/pmac_done.o src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ src/mac/pmac/pmac_memory_multi.o src/mac/pmac/pmac_ntz.o src/mac/pmac/pmac_process.o \ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/poly1305/poly1305.o \ src/mac/poly1305/poly1305_file.o src/mac/poly1305/poly1305_memory.o \ diff --git a/sources.cmake b/sources.cmake index 0d3ef35e0..4658c1b02 100644 --- a/sources.cmake +++ b/sources.cmake @@ -145,6 +145,11 @@ src/mac/hmac/hmac_memory.c src/mac/hmac/hmac_memory_multi.c src/mac/hmac/hmac_process.c src/mac/hmac/hmac_test.c +src/mac/kmac/kmac.c +src/mac/kmac/kmac_file.c +src/mac/kmac/kmac_memory.c +src/mac/kmac/kmac_memory_multi.c +src/mac/kmac/kmac_test.c src/mac/omac/omac_done.c src/mac/omac/omac_file.c src/mac/omac/omac_init.c