Implement "KDF in Counter Mode" from NIST SP 800-108.

This is currently instantiated with HMAC-SHA256 as the pseudo-random function, but is implemented using a template so that other PRFs could also be used.
This commit is contained in:
Stephen Heumann 2024-04-15 19:46:50 -05:00
parent d3d3dbbad9
commit 58a9c564ae
4 changed files with 110 additions and 1 deletions

View File

@ -31,7 +31,7 @@ sha1.a: sha1.cc sha1.h sha1.asm sha1.macros hmacimpl.h
$(CC) $(CFLAGS) -c $<
sha1.B: sha1.a
sha256.a: sha256.cc sha256.h sha256.asm sha256.macros hmacimpl.h
sha256.a: sha256.cc sha256.h sha256.asm sha256.macros hmacimpl.h kdfimpl.h
$(CC) $(CFLAGS) -c $<
sha256.B: sha256.a

89
kdfimpl.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file is a template for computing a key-derivation function
* ("KDF in Counter Mode" as specified in NIST SP 800-108), which may
* use various HMAC functions (among others) as a "pseudo-random function."
*
* This file is #included from the files implementing the hash functions,
* with KDF_PRF defined to the name of the pseudo-random function being used,
* and KDF_PRF_h defined to the width of its output in bits.
*/
#include <string.h>
#define join(a,b) a##b
#define concat(a,b) join(a,b)
#define KDF_PRF_init concat(KDF_PRF,_init)
#define KDF_PRF_update concat(KDF_PRF,_update)
#define KDF_PRF_finalize concat(KDF_PRF,_finalize)
#define KDF_PRF_result concat(KDF_PRF,_result)
#define KDF_PRF_context concat(KDF_PRF,_context)
#define KDF_PRF_kdf_ctr concat(KDF_PRF,_kdf_ctr)
/*
* This implements "KDF in Counter Mode" as specified in NIST SP 800-108.
* See that specification for details of its parameters.
*
* This implementation can be instantiated for various pseudo-random functions
* (e.g. HMACs). It assumes r = 32, and assumes big-endian byte order is used
* for integers. L must be a multiple of 8. The result buffer must be L bits
* (i.e. L/8 bytes) long. The PRF context structure must be provided for use
* within this function; its state at the beginning and end is not meaningful.
*/
void KDF_PRF_kdf_ctr(struct KDF_PRF_context *ctx,
const unsigned char *k_in, unsigned key_len,
unsigned long L, unsigned char *result,
const char *label, unsigned long label_len,
const char *context, unsigned long context_len)
{
unsigned long n, i;
static const char zero = 0;
unsigned long lastSize;
n = L / KDF_PRF_h;
lastSize = L % KDF_PRF_h;
if (lastSize != 0) {
n++;
} else {
lastSize = KDF_PRF_h;
}
for (i = 1; i && i <= n; i++) {
KDF_PRF_init(ctx, k_in, key_len);
KDF_PRF_update(ctx, (unsigned char *)&i + 3, 1);
KDF_PRF_update(ctx, (unsigned char *)&i + 2, 1);
KDF_PRF_update(ctx, (unsigned char *)&i + 1, 1);
KDF_PRF_update(ctx, (unsigned char *)&i + 0, 1);
KDF_PRF_update(ctx, label, label_len);
KDF_PRF_update(ctx, &zero, 1);
KDF_PRF_update(ctx, context, context_len);
KDF_PRF_update(ctx, (unsigned char *)&L + 3, 1);
KDF_PRF_update(ctx, (unsigned char *)&L + 2, 1);
KDF_PRF_update(ctx, (unsigned char *)&L + 1, 1);
KDF_PRF_update(ctx, (unsigned char *)&L + 0, 1);
KDF_PRF_finalize(ctx);
if (i != n) {
memcpy(result, KDF_PRF_result(ctx), KDF_PRF_h/8);
result += KDF_PRF_h/8;
} else {
memcpy(result, KDF_PRF_result(ctx), lastSize/8);
}
}
}

View File

@ -207,4 +207,8 @@ void sha256_finalize(struct sha256_context *context)
#define HASH_ALG sha256
#include "hmacimpl.h"
#define KDF_PRF hmac_sha256
#define KDF_PRF_h 256
#include "kdfimpl.h"
#append "sha256.asm"

View File

@ -101,3 +101,19 @@ void hmac_sha256_compute(struct hmac_sha256_context *context,
* or hmac_sha256_compute.
*/
#define hmac_sha256_result(context) ((context)->u[0].ctx.hash)
/*
* This implements "KDF in Counter Mode" as specified in NIST SP 800-108, with
* HMAC-SHA256 as the pseudo-random function. See that specification for
* details of its parameters.
*
* This implementation assumes r = 32 and assumes big-endian byte order is used
* for integers. L must be a multiple of 8. The result buffer must be L bits
* (i.e. L/8 bytes) long. The HMAC-SHA256 context must be provided for use
* within this function; its state at the beginning and end is not meaningful.
*/
void hmac_sha256_kdf_ctr(struct hmac_sha256_context *ctx,
const unsigned char *k_in, unsigned key_len,
unsigned long L, unsigned char *result,
const char *label, unsigned long label_len,
const char *context, unsigned long context_len);