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.master
@@ -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); | ||||
for (i=0; i < keylen; i++) { | |||||
buf[i+n] = key[i]; | |||||
} | |||||
for (i=0; i < inlen; i++) { | |||||
buf[keylen + n + i] = in[i]; | |||||
} | |||||
memcpy(buf + n, key, keylen); | |||||
memcpy(buf + keylen + n, in, inlen); | |||||
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] | ||||
*/ | */ | ||||
@@ -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 |
@@ -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 sm[params.sig_bytes + MLEN]; | |||||
unsigned char mout[params.sig_bytes + MLEN]; | |||||
unsigned char *m = malloc(MLEN); | |||||
unsigned char *sm = malloc(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; | ||||
} | } |
@@ -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(¶ms, oid); | XMSS_PARSE_OID(¶ms, 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 m[smlen]; | |||||
unsigned char *sm = malloc(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; | ||||
} | } |
@@ -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(¶ms, oid_sk); | XMSS_PARSE_OID(¶ms, 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 sm[params.sig_bytes + mlen]; | |||||
unsigned char *m = malloc(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; | |||||
} | } |
@@ -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.. */ | ||||
@@ -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] | ||||
@@ -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); | |||||
sm += params->n; | |||||
hash_message(params, mhash, sm + params->index_bytes, pub_root, idx, | |||||
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; | ||||
} | } |
@@ -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); | |||||
memcpy(hash_key+params->n, sk+4+3*params->n, params->n); | |||||
ull_to_bytes(hash_key+2*params->n, params->n, idx); | |||||
// Then use it for message digest | |||||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||||
/* 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); | |||||
/* 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 | |||||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||||
/* 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); | |||||
/* 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; | ||||