Support messages that exceed the stack size

Previous code allocated an array on the stack of mlen bytes, but
it should be possible to also sign heap-space messages. By relying
on the fact that sm and m fit the message + signature, we move
the message so that 4*n bytes of prefix can be added.
This commit is contained in:
Joost Rijneveld 2017-10-30 17:24:10 +01:00
parent f5d53b252e
commit 384b228c58
No known key found for this signature in database
GPG Key ID: A4FE39CF49CBC553
9 changed files with 108 additions and 72 deletions

60
hash.c
View File

@ -1,12 +1,13 @@
#include <stdint.h>
#include <string.h>
#include <openssl/sha.h>
#include "hash_address.h" #include "hash_address.h"
#include "xmss_commons.h" #include "xmss_commons.h"
#include "params.h" #include "params.h"
#include "hash.h" #include "hash.h"
#include "fips202.h" #include "fips202.h"
#include <stdint.h>
#include <openssl/sha.h>
void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8])
{ {
int i; int i;
@ -20,22 +21,13 @@ static int core_hash(const xmss_params *params,
const unsigned char *key, unsigned int keylen, const unsigned char *key, unsigned int keylen,
const unsigned char *in, unsigned long long inlen, int n) const unsigned char *in, unsigned long long inlen, int n)
{ {
unsigned long long i = 0;
unsigned char buf[inlen + n + keylen]; unsigned char buf[inlen + n + keylen];
/* We arrange the input into the hash function to be of the form: /* We arrange the input into the hash function to be of the form:
* toByte(X, 32) || KEY || M * toByte(X, 32) || KEY || M */
*/
ull_to_bytes(buf, n, type); ull_to_bytes(buf, n, type);
memcpy(buf + n, key, keylen);
for (i=0; i < keylen; i++) { memcpy(buf + keylen + n, in, inlen);
buf[i+n] = key[i];
}
for (i=0; i < inlen; i++) {
buf[keylen + n + i] = in[i];
}
if (n == 32 && params->func == XMSS_SHA2) { if (n == 32 && params->func == XMSS_SHA2) {
SHA256(buf, inlen + keylen + n, out); SHA256(buf, inlen + keylen + n, out);
@ -70,6 +62,44 @@ int h_msg(const xmss_params *params,
return core_hash(params, out, 2, key, keylen, in, inlen, params->n); return core_hash(params, out, 2, key, keylen, in, inlen, params->n);
} }
/*
* Computes the message hash using R, the public root, the index of the leaf
* node, and the message. Notably, it requires m_with_prefix to have 4*n bytes
* of space before the message, to use for the prefix. This is necessary to
* prevent having to move the message around (and thus allocate memory for it).
*/
int hash_message(const xmss_params *params, unsigned char *out,
const unsigned char *R, const unsigned char *root,
unsigned long long idx,
unsigned char *m_with_prefix, unsigned long long mlen)
{
/* We're creating a hash using input of the form:
toByte(X, 32) || R || root || index || M */
ull_to_bytes(m_with_prefix, params->n, 2);
memcpy(m_with_prefix + params->n, R, params->n);
memcpy(m_with_prefix + 2 * params->n, root, params->n);
ull_to_bytes(m_with_prefix + 3 * params->n, params->n, idx);
/* Since the message can be bigger than the stack, this cannot use the
* core_hash function. */
if (params->n == 32 && params->func == XMSS_SHA2) {
SHA256(m_with_prefix, mlen + 4*params->n, out);
}
else if (params->n == 32 && params->func == XMSS_SHAKE) {
shake128(out, 32, m_with_prefix, mlen + 4*params->n);
}
else if (params->n == 64 && params->func == XMSS_SHA2) {
SHA512(m_with_prefix, mlen + 4*params->n, out);
}
else if (params->n == 64 && params->func == XMSS_SHAKE) {
shake256(out, 64, m_with_prefix, mlen + 4*params->n);
}
else {
return 1;
}
return 0;
}
/** /**
* We assume the left half is in in[0]...in[n-1] * We assume the left half is in in[0]...in[n-1]
*/ */

5
hash.h
View File

@ -23,4 +23,9 @@ int hash_f(const xmss_params *params,
unsigned char *out, const unsigned char *in, unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]); const unsigned char *pub_seed, uint32_t addr[8]);
int hash_message(const xmss_params *params, unsigned char *out,
const unsigned char *R, const unsigned char *root,
unsigned long long idx,
unsigned char *m_with_prefix, unsigned long long mlen);
#endif #endif

View File

@ -1,9 +1,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "../xmss.h" #include "../xmss.h"
#include "../params.h" #include "../params.h"
#include "../randombytes.h"
#define MLEN 32 #define MLEN 32
#define SIGNATURES 16 #define SIGNATURES 16
@ -33,12 +35,14 @@ int main()
unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; unsigned char pk[XMSS_OID_LEN + params.pk_bytes];
unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; unsigned char sk[XMSS_OID_LEN + params.sk_bytes];
unsigned char m[MLEN]; unsigned char *m = malloc(MLEN);
unsigned char sm[params.sig_bytes + MLEN]; unsigned char *sm = malloc(params.sig_bytes + MLEN);
unsigned char mout[params.sig_bytes + MLEN]; unsigned char *mout = malloc(params.sig_bytes + MLEN);
unsigned long long smlen; unsigned long long smlen;
unsigned long long mlen; unsigned long long mlen;
randombytes(m, MLEN);
XMSS_KEYPAIR(pk, sk, oid); XMSS_KEYPAIR(pk, sk, oid);
printf("Testing %d %s signatures.. \n", SIGNATURES, XMSS_VARIANT); printf("Testing %d %s signatures.. \n", SIGNATURES, XMSS_VARIANT);
@ -106,5 +110,9 @@ int main()
} }
} }
free(m);
free(sm);
free(mout);
return 0; return 0;
} }

View File

@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "../params.h" #include "../params.h"
#include "../xmss.h" #include "../xmss.h"
@ -49,8 +50,8 @@ int main(int argc, char **argv) {
XMSS_PARSE_OID(&params, oid); XMSS_PARSE_OID(&params, oid);
unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; unsigned char pk[XMSS_OID_LEN + params.pk_bytes];
unsigned char sm[smlen]; unsigned char *sm = malloc(smlen);
unsigned char m[smlen]; unsigned char *m = malloc(smlen);
unsigned long long mlen; unsigned long long mlen;
fseek(keypair_file, 0, SEEK_SET); fseek(keypair_file, 0, SEEK_SET);
@ -70,5 +71,8 @@ int main(int argc, char **argv) {
fclose(keypair_file); fclose(keypair_file);
fclose(sm_file); fclose(sm_file);
free(m);
free(sm);
return ret; return ret;
} }

View File

@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "../params.h" #include "../params.h"
#include "../xmss.h" #include "../xmss.h"
@ -56,8 +57,8 @@ int main(int argc, char **argv) {
XMSS_PARSE_OID(&params, oid_sk); XMSS_PARSE_OID(&params, oid_sk);
unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; unsigned char sk[XMSS_OID_LEN + params.sk_bytes];
unsigned char m[mlen]; unsigned char *m = malloc(mlen);
unsigned char sm[params.sig_bytes + mlen]; unsigned char *sm = malloc(params.sig_bytes + mlen);
unsigned long long smlen; unsigned long long smlen;
/* fseek back to start of sk. */ /* fseek back to start of sk. */
@ -74,4 +75,9 @@ int main(int argc, char **argv) {
fclose(keypair_file); fclose(keypair_file);
fclose(m_file); fclose(m_file);
free(m);
free(sm);
return 0;
} }

View File

@ -115,25 +115,6 @@ void l_tree(const xmss_params *params,
memcpy(leaf, wots_pk, params->n); memcpy(leaf, wots_pk, params->n);
} }
/**
* Computes the randomized message hash.
*/
void hash_message(const xmss_params *params, unsigned char *mhash,
const unsigned char *R, const unsigned char *root,
unsigned long long idx,
const unsigned char *m, unsigned long long mlen)
{
unsigned char hash_key[3*params->n];
/* Compute hash key. */
memcpy(hash_key, R, params->n);
memcpy(hash_key + params->n, root, params->n);
ull_to_bytes(hash_key + 2*params->n, params->n, idx);
/* Hash the message using the randomized hash key. */
h_msg(params, mhash, m, mlen, hash_key, 3*params->n);
}
/** /**
* Computes a root node given a leaf and an auth path * Computes a root node given a leaf and an auth path
*/ */
@ -228,9 +209,13 @@ int xmssmt_core_sign_open(const xmss_params *params,
/* Convert the index bytes from the signature to an integer. */ /* Convert the index bytes from the signature to an integer. */
idx = bytes_to_ull(sm, params->index_bytes); idx = bytes_to_ull(sm, params->index_bytes);
/* Put the message all the way at the end of the m buffer, so that we can
* prepend the required other inputs for the hash function. */
memcpy(m + params->sig_bytes, sm + params->sig_bytes, *mlen);
/* Compute the message hash. */ /* Compute the message hash. */
hash_message(params, mhash, sm + params->index_bytes, pk, idx, hash_message(params, mhash, sm + params->index_bytes, pk, idx,
sm + params->sig_bytes, *mlen); m + params->sig_bytes - 4*params->n, *mlen);
sm += params->index_bytes + params->n; sm += params->index_bytes + params->n;
/* For each subtree.. */ /* For each subtree.. */

View File

@ -41,14 +41,6 @@ void l_tree(const xmss_params *params,
unsigned char *leaf, unsigned char *wots_pk, unsigned char *leaf, unsigned char *wots_pk,
const unsigned char *pub_seed, uint32_t addr[8]); const unsigned char *pub_seed, uint32_t addr[8]);
/**
* Computes the randomized message hash.
*/
void hash_message(const xmss_params *params, unsigned char *mhash,
const unsigned char *R, const unsigned char *root,
unsigned long long idx,
const unsigned char *m, unsigned long long mlen);
/** /**
* Verifies a given message signature pair under a given public key. * Verifies a given message signature pair under a given public key.
* Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED]

View File

@ -189,10 +189,14 @@ int xmssmt_core_sign(const xmss_params *params,
uint32_t ots_addr[8] = {0}; uint32_t ots_addr[8] = {0};
set_type(ots_addr, XMSS_ADDR_TYPE_OTS); set_type(ots_addr, XMSS_ADDR_TYPE_OTS);
/* Already put the message in the right place, to make it easier to prepend
* things when computing the hash over the message. */
memcpy(sm + params->sig_bytes, m, mlen);
*smlen = params->sig_bytes + mlen;
/* Read and use the current index from the secret key. */ /* Read and use the current index from the secret key. */
idx = (unsigned long)bytes_to_ull(sk, params->index_bytes); idx = (unsigned long)bytes_to_ull(sk, params->index_bytes);
memcpy(sm, sk, params->index_bytes); memcpy(sm, sk, params->index_bytes);
sm += params->index_bytes;
/************************************************************************* /*************************************************************************
* THIS IS WHERE PRODUCTION IMPLEMENTATIONS WOULD UPDATE THE SECRET KEY. * * THIS IS WHERE PRODUCTION IMPLEMENTATIONS WOULD UPDATE THE SECRET KEY. *
@ -202,11 +206,12 @@ int xmssmt_core_sign(const xmss_params *params,
/* Compute the digest randomization value. */ /* Compute the digest randomization value. */
ull_to_bytes(idx_bytes_32, 32, idx); ull_to_bytes(idx_bytes_32, 32, idx);
prf(params, sm, idx_bytes_32, sk_prf, params->n); prf(params, sm + params->index_bytes, idx_bytes_32, sk_prf, params->n);
/* Compute the message hash. */ /* Compute the message hash. */
hash_message(params, mhash, sm, pub_root, idx, m, mlen); hash_message(params, mhash, sm + params->index_bytes, pub_root, idx,
sm += params->n; sm + params->sig_bytes - 4*params->n, mlen);
sm += params->index_bytes + params->n;
set_type(ots_addr, XMSS_ADDR_TYPE_OTS); set_type(ots_addr, XMSS_ADDR_TYPE_OTS);
@ -232,8 +237,5 @@ int xmssmt_core_sign(const xmss_params *params,
sm += params->tree_height*params->n; sm += params->tree_height*params->n;
} }
memcpy(sm, m, mlen);
*smlen = params->sig_bytes + mlen;
return 0; return 0;
} }

View File

@ -393,6 +393,8 @@ int xmss_core_sign(const xmss_params *params,
unsigned char *sm, unsigned long long *smlen, unsigned char *sm, unsigned long long *smlen,
const unsigned char *m, unsigned long long mlen) const unsigned char *m, unsigned long long mlen)
{ {
const unsigned char *pub_root = sk + params->index_bytes + 3*params->n;
uint16_t i = 0; uint16_t i = 0;
// Extract SK // Extract SK
@ -408,8 +410,6 @@ int xmss_core_sign(const xmss_params *params,
unsigned char idx_bytes_32[32]; unsigned char idx_bytes_32[32];
ull_to_bytes(idx_bytes_32, 32, idx); ull_to_bytes(idx_bytes_32, 32, idx);
unsigned char hash_key[3*params->n];
// Update SK // Update SK
sk[0] = ((idx + 1) >> 24) & 255; sk[0] = ((idx + 1) >> 24) & 255;
sk[1] = ((idx + 1) >> 16) & 255; sk[1] = ((idx + 1) >> 16) & 255;
@ -432,12 +432,14 @@ int xmss_core_sign(const xmss_params *params,
// Message Hash: // Message Hash:
// First compute pseudorandom value // First compute pseudorandom value
prf(params, R, idx_bytes_32, sk_prf, params->n); prf(params, R, idx_bytes_32, sk_prf, params->n);
// Generate hash key (R || root || idx)
memcpy(hash_key, R, params->n); /* Already put the message in the right place, to make it easier to prepend
memcpy(hash_key+params->n, sk+4+3*params->n, params->n); * things when computing the hash over the message. */
ull_to_bytes(hash_key+2*params->n, params->n, idx); memcpy(sm + params->sig_bytes, m, mlen);
// Then use it for message digest
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); /* Compute the message hash. */
hash_message(params, msg_h, R, pub_root, idx,
sm + params->sig_bytes - 4*params->n, mlen);
// Start collecting signature // Start collecting signature
*smlen = 0; *smlen = 0;
@ -554,6 +556,8 @@ int xmssmt_core_sign(const xmss_params *params,
unsigned char *sm, unsigned long long *smlen, unsigned char *sm, unsigned long long *smlen,
const unsigned char *m, unsigned long long mlen) const unsigned char *m, unsigned long long mlen)
{ {
const unsigned char *pub_root = sk + params->index_bytes + 3*params->n;
uint64_t idx_tree; uint64_t idx_tree;
uint32_t idx_leaf; uint32_t idx_leaf;
uint64_t i, j; uint64_t i, j;
@ -566,7 +570,6 @@ int xmssmt_core_sign(const xmss_params *params,
// Init working params // Init working params
unsigned char R[params->n]; unsigned char R[params->n];
unsigned char msg_h[params->n]; unsigned char msg_h[params->n];
unsigned char hash_key[3*params->n];
unsigned char ots_seed[params->n]; unsigned char ots_seed[params->n];
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
@ -599,13 +602,14 @@ int xmssmt_core_sign(const xmss_params *params,
// First compute pseudorandom value // First compute pseudorandom value
ull_to_bytes(idx_bytes_32, 32, idx); ull_to_bytes(idx_bytes_32, 32, idx);
prf(params, R, idx_bytes_32, sk_prf, params->n); prf(params, R, idx_bytes_32, sk_prf, params->n);
// Generate hash key (R || root || idx)
memcpy(hash_key, R, params->n);
memcpy(hash_key+params->n, sk+params->index_bytes+3*params->n, params->n);
ull_to_bytes(hash_key+2*params->n, params->n, idx);
// Then use it for message digest /* Already put the message in the right place, to make it easier to prepend
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); * things when computing the hash over the message. */
memcpy(sm + params->sig_bytes, m, mlen);
/* Compute the message hash. */
hash_message(params, msg_h, R, pub_root, idx,
sm + params->sig_bytes - 4*params->n, mlen);
// Start collecting signature // Start collecting signature
*smlen = 0; *smlen = 0;