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:
parent
d3d3dbbad9
commit
58a9c564ae
2
Makefile
2
Makefile
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
16
sha256.h
16
sha256.h
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue