Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add XMSS secret key objects APIs, sync with LMS #1587

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Na lms (#1486)
* Add base LMS library

* ignore use of free() by adding // IGNORE free-check

* ignore use of free() by adding // IGNORE free-check
  • Loading branch information
ashman-p authored and dstebila committed Aug 18, 2023
commit f313b919aec45b9558470c5e5b66964133b9edc0
178 changes: 178 additions & 0 deletions src/sig_stfl/lms/external/common_defs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#if !defined( COMMON_DEFS_H_ )
#define COMMON_DEFS_H_

/*
* These are defintions for the LMS implementation that are common throughout
* the system (and so are collected in one place)
*/

#include <stdint.h>
#include <stdbool.h>

#define MAX_HASH 32 /* Length of the largest hash we support */

/* The I (Merkle tree identifier) value is 16 bytes long */
#define I_LEN 16

/* The maximum height of a Merkle tree */
#define MAX_MERKLE_HEIGHT 25

/* The mininum height of a Merkle tree. Some of our update logic assumes */
/* this isn't too small */
#define MIN_MERKLE_HEIGHT 5

/* The minimum/maximum number of levels of Merkle trees within an HSS trees */
#define MIN_HSS_LEVELS 1 /* Minumum levels we allow */
#define MAX_HSS_LEVELS 8 /* Maximum levels we allow */

/* This is the length of our internal seed values */
#define SEED_LEN 32 /* Enough to make Grover's infeasible */

/* Here are some internal types used within the code. They are listed more */
/* for documentation ("this is what this variable is expected to be") rather */
/* than to let the compiler do any sort of type checking */

/* This is an index into a Merkle tree */
/* Used for both the leaf index (0..N-1) and the node number (1..2*N-1), */
/* where N is the size 2**h of the tre */
#if MAX_MERKLE_HEIGHT > 31
/* We need to express more than 32 bits in this type */
typedef uint_fast64_t merkle_index_t;
#error We need to extend the id we place within a hash to more than 4 bytes
#else
typedef uint_fast32_t merkle_index_t;
#endif

/* This is the name of a parameter set */
/* Used for both an OTS parameter set or an LM parameter set */
/* Both are 32 bits */
typedef uint_fast32_t param_set_t;

/* This is a sequence number over an HSS tree */
/* This means we can never generate more than 2**64 signatures from a */
/* private key (even if the parameter set would, in theory, allow us */
/* to do more) */
typedef uint_fast64_t sequence_t;

/* Defined LM parameter sets */
#define LMS_SHA256_N32_H5 0x00000005
#define LMS_SHA256_N32_H10 0x00000006
#define LMS_SHA256_N32_H15 0x00000007
#define LMS_SHA256_N32_H20 0x00000008
#define LMS_SHA256_N32_H25 0x00000009

/* LM-OTS registry */
#define LMOTS_SHA256_N32_W1 0x00000001
#define LMOTS_SHA256_N32_W2 0x00000002
#define LMOTS_SHA256_N32_W4 0x00000003
#define LMOTS_SHA256_N32_W8 0x00000004

/*
* Internal formats of various hashes
*
* We do a number of different hashes as a part of this package; some
* specified by the draft, some specific to us.
* For each such hash, we list the values being hashed, and the offset
* from the start where they go. We treat them as indicies into unsigned char
* arrays, and not structs, to avoid any potential padding issues with structs
*
* For a hash of type XXXX, XXXX_Z is the offset where component Z goes,
* XXXX_LEN(hash_len) is the length being hashed (assuming that hash length),
* XXXX_MAXLEN is the maximum length it can be (for allocation), and D_XXXX
* is the hash distinguisher (the value that makes it different from any other
* hash)
*/

/* The initial message hashing */
#define MESG_I 0
#define MESG_Q 16
#define MESG_D 20 /* The fixed D_MESG value */
#define MESG_C 22
#define MESG_PREFIX_LEN(n) (MESG_C + (n)) /* Length not counting the actual */
/* message being signed */
#define MESG_PREFIX_MAXLEN MESG_PREFIX_LEN(MAX_HASH)
#define D_MESG 0x8181

/* The Winternitz iteration hashes */
#define ITER_I 0
#define ITER_Q 16
#define ITER_K 20 /* The RFC uses i here */
#define ITER_J 22
#define ITER_PREV 23 /* Hash from previous iteration; RFC uses tmp */
#define ITER_LEN(hash_len) (ITER_PREV + (hash_len))
#define ITER_MAX_LEN ITER_LEN(MAX_HASH)

/* Hashing the OTS public key */
#define PBLC_I 0
#define PBLC_Q 16
#define PBLC_D 20 /* The fixed D_PBLC value */
#define PBLC_PREFIX_LEN 22 /* Not counting the OTS public keys */
#define D_PBLC 0x8080

/* Hashing Merkle tree leaf nodes */
#define LEAF_I 0
#define LEAF_R 16
#define LEAF_D 20
#define LEAF_PK 22
#define LEAF_LEN(root_len) (LEAF_PK + (root_len))
#define LEAF_MAX_LEN LEAF_LEN(MAX_HASH)
#define D_LEAF 0x8282

/* Hashing Merkle tree internal nodes */
#define INTR_I 0
#define INTR_R 16
#define INTR_D 20
#define INTR_PK 22
#define INTR_LEN(root_len) (INTR_PK + 2 * (root_len))
#define INTR_MAX_LEN INTR_LEN(MAX_HASH)
#define D_INTR 0x8383

/* The determanistic key generation */
/* Also used to generate subkeys in the j-tree hierarchy */
/* As we'll always do either one or the other, we can reuse the structure */
/* for both purposes */
#define PRG_I 0
#define PRG_Q 16
#define PRG_J 20
#define PRG_FF 22 /* A fixed 0xff goes here */
#define PRG_SEED 23
#define PRG_LEN(seed_len) (23 + (seed_len))
#define PRG_MAX_LEN PRG_LEN(MAX_HASH)

/* The below are hash formats that the draft does not list, but we */
/* implement ourselves (largely because we need to be determanistic */
/* based on the seed) */

/* Hash used to generate subkeys in the q tree hierarchy */
#define QTREE_I 0
#define QTREE_Q 16
#define QTREE_D 20 /* D_QTREE goes here */
#define QTREE_SEED 22
#define QTREE_LEN (22 + 32) /* We assume a fixed length seed */
#define QTREE_MAX_LEN QTREE_LEN
#define D_QTREE 0xffff

/* Hash used to generate the master seed for the top level Merkle tree */
#define TOPSEED_I 0 /* 16 0's here (we don't have an I value) */
#define TOPSEED_Q 16 /* 0's here (as we don't have a Q value) */
#define TOPSEED_D 20 /* D_TOPSEED */
#define TOPSEED_WHICH 22 /* 0 -> Gen Master seed (used as seed for */
/* the next two) */
/* 1 -> Create top level seed */
/* 2 -> Create top level I */
#define TOPSEED_SEED 23 /* 32 bytes long */
#define TOPSEED_LEN (TOPSEED_SEED + 32)
#define D_TOPSEED 0xfefe

/* Hash used to generate the key used for the authenticating the aux values */
#define DAUX_I 0 /* 16 0's here (no I value) */
#define DAUX_Q 16 /* 4 more 0's here (no Q value) */
#define DAUX_D 20 /* D_AUX_SEED_DERIVE */
#define DAUX_PREFIX_LEN 22 /* Not counting the seed value */
#define D_DAUX 0xfdfd

/* Macro to set the D_XXXX value to the XXXX_D offset */
#define SET_D(p, value) (void)(((p)[0] = (value) >> 8), \
((p)[1] = (value) & 0xff))

#endif /* COMMON_DEFS_H_ */
36 changes: 36 additions & 0 deletions src/sig_stfl/lms/external/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#if !defined( CONFIG_H_ )
#define CONFIG_H_

#define LMS_UNUSED(x) (void)(x)

/*
* This file has #define's that specify how this package operates, and
* are designed to be tweaked by the user.
*
* These can be adjusted to be appropriate for what the application and
* the operating environment needs
*/

/*
* This modifies which seed generation logic we use
* Note that changing these parameters will change the mapping
* between private keys.
*
* 0 -> We generate seeds using the process defined in Appendix A of the draft
* This is slightly faster
* 1 -> We use a side channel resistant process, never using any single secret
* seed in more than a defined number of distinct hashes
* 2 -> We generate seeds and secrets in a way which is compatible with ACVP
*/
#define SECRET_METHOD 2

/*
* If we're using the side channel resistant method, this defines the max
* number of times we'll use a single secret. Note that this is the log2
* of the max number of times, and so 3 means 'no more than 8 times'
* Reducing SECRET_MAX is a bit more costly; however I don't know that if
* it is significant
*/
#define SECRET_MAX 4 /* Never use a seed more than 16 times */

#endif /* CONFIG_H_ */
23 changes: 23 additions & 0 deletions src/sig_stfl/lms/external/endian.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "endian.h"

void put_bigendian( void *target, unsigned long long value, size_t bytes ) {
unsigned char *b = target;
int i;

for (i = bytes-1; i >= 0; i--) {
b[i] = value & 0xff;
value >>= 8;
}
}

unsigned long long get_bigendian( const void *target, size_t bytes ) {
const unsigned char *b = target;
unsigned long long result = 0;
size_t i;

for (i=0; i<bytes; i++) {
result = 256 * result + (b[i] & 0xff);
}

return result;
}
9 changes: 9 additions & 0 deletions src/sig_stfl/lms/external/endian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#if !defined( ENDIAN_H_ )
#define ENDIAN_H_

#include <stddef.h>

void put_bigendian( void *target, unsigned long long value, size_t bytes );
unsigned long long get_bigendian( const void *target, size_t bytes );

#endif /* ENDIAN_H_ */
119 changes: 119 additions & 0 deletions src/sig_stfl/lms/external/hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include <string.h>
#include "hash.h"
#include "sha256.h"
#include "hss_zeroize.h"

#define ALLOW_VERBOSE 0 /* 1 -> we allow the dumping of intermediate */
/* states. Useful for debugging; horrid */
/* for security */

/*
* This is the file that implements the hashing APIs we use internally.
* At the present, our parameter sets support only one hash function
* (SHA-256, using full 256 bit output), however, that is likely to change
* in the future
*/

#if ALLOW_VERBOSE
#include <stdio.h>
#include <stdbool.h>
/*
* Debugging flag; if this is set, we chat about what we're hashing, and what
* the result is it's useful when debugging; however we probably don't want to
* do this if we're multithreaded...
*/
bool hss_verbose = false;
#endif

/*
* This will hash the message, given the hash type. It assumes that the result
* buffer is large enough for the hash
*/
void hss_hash_ctx(void *result, int hash_type, union hash_context *ctx,
const void *message, size_t message_len) {
#if ALLOW_VERBOSE
if (hss_verbose) {
int i; for (i=0; i< message_len; i++) printf( " %02x%s", ((unsigned char*)message)[i], (i%16 == 15) ? "\n" : "" );
}
#endif

switch (hash_type) {
case HASH_SHA256: {
SHA256_Init(&ctx->sha256);
SHA256_Update(&ctx->sha256, message, message_len);
SHA256_Final(result, &ctx->sha256);
#if ALLOW_VERBOSE
if (hss_verbose) {
printf( " ->" );
int i; for (i=0; i<32; i++) printf( " %02x", ((unsigned char *)result)[i] ); printf( "\n" );
}
#endif
break;
}
}
}

void hss_hash(void *result, int hash_type,
const void *message, size_t message_len) {
union hash_context ctx;
hss_hash_ctx(result, hash_type, &ctx, message, message_len);
hss_zeroize(&ctx, sizeof ctx);
}


/*
* This provides an API to do incremental hashing. We use it when hashing the
* message; since we don't know how long it could be, we don't want to
* allocate a buffer that's long enough for that, plus the decoration we add
*/
void hss_init_hash_context(int h, union hash_context *ctx) {
switch (h) {
case HASH_SHA256:
SHA256_Init( &ctx->sha256 );
break;
}
}

void hss_update_hash_context(int h, union hash_context *ctx,
const void *msg, size_t len_msg) {
#if ALLOW_VERBOSE
if (hss_verbose) {
int i; for (i=0; i<len_msg; i++) printf( " %02x", ((unsigned char*)msg)[i] );
}
#endif
switch (h) {
case HASH_SHA256:
SHA256_Update(&ctx->sha256, msg, len_msg);
break;
}
}

void hss_finalize_hash_context(int h, union hash_context *ctx, void *buffer) {
switch (h) {
case HASH_SHA256:
SHA256_Final(buffer, &ctx->sha256);
#if ALLOW_VERBOSE
if (hss_verbose) {
printf( " -->" );
int i; for (i=0; i<32; i++) printf( " %02x", ((unsigned char*)buffer)[i] );
printf( "\n" );
}
#endif
break;
}
}


unsigned hss_hash_length(int hash_type) {
switch (hash_type) {
case HASH_SHA256: return 32;
}
return 0;
}

unsigned hss_hash_blocksize(int hash_type) {
switch (hash_type) {
case HASH_SHA256: return 64;
}
return 0;
}
Loading