Merge pull request #759 from libtom/pr/KMAC128-256

KMAC as defined in NIST SP 800-185
This commit is contained in:
Steffen Jaeckel 2026-05-19 13:05:06 +02:00 committed by GitHub
commit 8512e3e891
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 708 additions and 20 deletions

View file

@ -3981,6 +3981,112 @@ int blake2bmac_file( const char *fname,
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

View file

@ -1159,6 +1159,30 @@
>
</File>
</Filter>
<Filter
Name="kmac"
>
<File
RelativePath="src\mac\kmac\kmac.c"
>
</File>
<File
RelativePath="src\mac\kmac\kmac_file.c"
>
</File>
<File
RelativePath="src\mac\kmac\kmac_memory.c"
>
</File>
<File
RelativePath="src\mac\kmac\kmac_memory_multi.c"
>
</File>
<File
RelativePath="src\mac\kmac\kmac_test.c"
>
</File>
</Filter>
<Filter
Name="omac"
>

View file

@ -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 \

View file

@ -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 \

View file

@ -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 \

View file

@ -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 \

View file

@ -146,6 +146,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

View file

@ -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);

View file

@ -301,6 +301,7 @@
#define LTC_POLY1305
#define LTC_BLAKE2SMAC
#define LTC_BLAKE2BMAC
#define LTC_KMAC
/* ---> Encrypt + Authenticate Modes <--- */
@ -735,6 +736,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

View file

@ -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);

View file

@ -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);

171
src/mac/kmac/kmac.c Normal file
View file

@ -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

90
src/mac/kmac/kmac_file.c Normal file
View file

@ -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

View file

@ -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

View file

@ -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

123
src/mac/kmac/kmac_test.c Normal file
View file

@ -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

View file

@ -288,6 +288,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)

View file

@ -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());