|
|
|
@ -30,6 +30,72 @@
|
|
|
|
|
|
|
|
|
|
#include "util.h" |
|
|
|
|
|
|
|
|
|
/** @file secret.c
|
|
|
|
|
* Secret splitting module. |
|
|
|
|
* |
|
|
|
|
* How to use this module to split a secret. |
|
|
|
|
* |
|
|
|
|
* Create a secret object and fills it with the secret data: |
|
|
|
|
* \code |
|
|
|
|
* gfsec_secret_t *secret = gfsec_secret_new(); |
|
|
|
|
* gfsec_secret_set_secret(filename); |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
* Create share objects describing the shares to split the |
|
|
|
|
* secret into, and add them to the secret object: |
|
|
|
|
* \code |
|
|
|
|
* gfsec_share_t *share = gfsec_share_new(); |
|
|
|
|
* gfsec_share_set_info(share, GFSEC_SHARE_NUMBER_AUTOASSIGN, |
|
|
|
|
* GFSEC_SCHEME_FILE, authority, path, NULL); |
|
|
|
|
* gfsec_secret_add_share(secret, share); |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
* Actually split the secret and write the shares' data: |
|
|
|
|
* \code |
|
|
|
|
* gfsec_secret_split(secret, threshold); |
|
|
|
|
* for ( int i = 0; i < secret->n_shares; i++ ) { |
|
|
|
|
* gfsec_share_t *share = secret->shares[i]; |
|
|
|
|
* write_data_somewhere(share->data, share->len); |
|
|
|
|
* } |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* How to use this module to reconstitute a secret. |
|
|
|
|
* |
|
|
|
|
* Create a secret object: |
|
|
|
|
* \code |
|
|
|
|
* gfsec_secret_t *secret = gfsec_secret_new(); |
|
|
|
|
* secret->threshold = threshold; |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
* Create share objects describing the shares, and add them |
|
|
|
|
* to the secret object: |
|
|
|
|
* \code |
|
|
|
|
* gfsec_share_t *share = gfsec_share_new(); |
|
|
|
|
* gfsec_share_set_info(share, share_number, GFSEC_SCHEME_FILE, |
|
|
|
|
* authority, path, hash); |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
* Fill the shares with data if available: |
|
|
|
|
* \code |
|
|
|
|
* gfsec_share_set_data(share, data, len); |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
* Actually reconstitute the secret: |
|
|
|
|
* \code |
|
|
|
|
* if ( gfsec_secret_can_recombine(secret) ) { |
|
|
|
|
* gfsec_secret_recombine(secret); |
|
|
|
|
* do_something_with_secret(secret->data, secret->len); |
|
|
|
|
* } |
|
|
|
|
* \endcode |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initializes a new share object. |
|
|
|
|
* |
|
|
|
|
* @return The share object, or NULL if memory could not be allocated. |
|
|
|
|
*/ |
|
|
|
|
gfsec_share_t * |
|
|
|
|
gfsec_share_new(void) |
|
|
|
|
{ |
|
|
|
@ -50,6 +116,26 @@ gfsec_share_new(void)
|
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fills the fields of a share object. |
|
|
|
|
* Note that all strings are copied to newly allocated buffers. |
|
|
|
|
* The gfsec_share_free function takes care of freeing those buffers. |
|
|
|
|
* |
|
|
|
|
* @param share The share object; |
|
|
|
|
* @param number The share number; should be between 1 and 255 |
|
|
|
|
* (inclusive) for a normal share, 0 for a share |
|
|
|
|
* which contains the whole secret, or |
|
|
|
|
* GFSEC_SHARE_NUMBER_AUTOASSIGN to let the |
|
|
|
|
* gfsec_secret_split function assign a share |
|
|
|
|
* number automatically; |
|
|
|
|
* @param scheme The scheme of the URI locating the share; |
|
|
|
|
* @param authority The authority part of the URI (may be NULL); |
|
|
|
|
* @param path The path part of the URI (may be NULL); |
|
|
|
|
* @param hash A buffer containing a SHA-256 hash of the |
|
|
|
|
* share's data (may be NULL). |
|
|
|
|
* |
|
|
|
|
* @return 0 if successful, or one of the GFSEC_ERR_* error codes. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_share_set_info(gfsec_share_t *share, |
|
|
|
|
unsigned char number, |
|
|
|
@ -64,9 +150,9 @@ gfsec_share_set_info(gfsec_share_t *share,
|
|
|
|
|
share->number = number; |
|
|
|
|
|
|
|
|
|
share->scheme = scheme; |
|
|
|
|
if ( ! (share->authority = strdup(authority)) ) |
|
|
|
|
if ( authority && ! (share->authority = strdup(authority)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( ! (share->path = strdup(path)) ) |
|
|
|
|
if ( path && ! (share->path = strdup(path)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
if ( hash ) |
|
|
|
@ -75,6 +161,20 @@ gfsec_share_set_info(gfsec_share_t *share,
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fills a share object with the corresponding data. |
|
|
|
|
* If the share object specifies a hash value, the data are |
|
|
|
|
* checked against this hash, and GFSEC_ERR_INVALID_SHARE is |
|
|
|
|
* returned if the checksum fails. |
|
|
|
|
* |
|
|
|
|
* @param share The share object. |
|
|
|
|
* @param data The buffer containing the data; only the pointer |
|
|
|
|
* is copied, not the buffer itself, and it will be |
|
|
|
|
* freed when the gfsec_share_free function is called; |
|
|
|
|
* @param len The size of the data buffer. |
|
|
|
|
* |
|
|
|
|
* @return 0 if successfull, or one of the GFSEC_ERR_* error codes. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_share_set_data(gfsec_share_t *share, |
|
|
|
|
unsigned char *data, |
|
|
|
@ -90,25 +190,29 @@ gfsec_share_set_data(gfsec_share_t *share,
|
|
|
|
|
ret = 0; |
|
|
|
|
|
|
|
|
|
if ( share->hash ) { |
|
|
|
|
gcry_md_hd_t md; |
|
|
|
|
unsigned char *hash; |
|
|
|
|
unsigned char hash[32]; |
|
|
|
|
|
|
|
|
|
gcry_md_open(&md, GCRY_MD_SHA256, 0); |
|
|
|
|
|
|
|
|
|
gcry_md_write(md, data, len); |
|
|
|
|
hash = gcry_md_read(md, 0); |
|
|
|
|
gcry_md_hash_buffer(GCRY_MD_SHA256, hash, data, len); |
|
|
|
|
if ( memcmp(share->hash, hash, 32) != 0 ) { |
|
|
|
|
ret = GFSEC_ERR_INVALID_SHARE; |
|
|
|
|
share->data = NULL; |
|
|
|
|
share->len = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gcry_md_close(md); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the URI representing the location of a share. |
|
|
|
|
* |
|
|
|
|
* @param share The share object. |
|
|
|
|
* @param buffer The buffer to write the URI into. |
|
|
|
|
* @param len The size of the buffer. |
|
|
|
|
* |
|
|
|
|
* @return The number of characters written into the buffer, |
|
|
|
|
* or GFSEC_ERR_INVALID_CALL if an invalid poitner was passed. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_share_get_uri(gfsec_share_t *share, |
|
|
|
|
char *buffer, |
|
|
|
@ -128,6 +232,11 @@ gfsec_share_get_uri(gfsec_share_t *share,
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Frees a share object and all of its buffers. |
|
|
|
|
* |
|
|
|
|
* @param share The share object. |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
gfsec_share_free(gfsec_share_t *share) |
|
|
|
|
{ |
|
|
|
@ -147,6 +256,11 @@ gfsec_share_free(gfsec_share_t *share)
|
|
|
|
|
free(share); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initializes a new secret object. |
|
|
|
|
* |
|
|
|
|
* @return The secret object, or NULL if memory could not be allocated. |
|
|
|
|
*/ |
|
|
|
|
gfsec_secret_t * |
|
|
|
|
gfsec_secret_new(void) |
|
|
|
|
{ |
|
|
|
@ -171,6 +285,14 @@ gfsec_secret_new(void)
|
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the secret to be splitted. |
|
|
|
|
* |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* @param filename The location of the file to read the secret from. |
|
|
|
|
* |
|
|
|
|
* @return 0 if successful, or one of the GFSEC_ERR_* error codes. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_set_secret_file(gfsec_secret_t *secret, |
|
|
|
|
const char *filename) |
|
|
|
@ -183,8 +305,23 @@ gfsec_secret_set_secret_file(gfsec_secret_t *secret,
|
|
|
|
|
|
|
|
|
|
if ( ! (secret->data = read_file(filename, &(secret->len))) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds a share to a secret object. |
|
|
|
|
* |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* @param share The share to add. |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if successful; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if improperly called; |
|
|
|
|
* - GFSEC_ERR_TOO_MANY_SHARES if the secret object already has the |
|
|
|
|
* maximal number of shares allowed; |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if a memory allocation error occurs. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_add_share(gfsec_secret_t *secret, gfsec_share_t *share) |
|
|
|
|
{ |
|
|
|
@ -231,10 +368,22 @@ gfsec_secret_add_share(gfsec_secret_t *secret, gfsec_share_t *share)
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if the secret can be reconstituted. |
|
|
|
|
* Note that it is mandatory to call this function prior to calling |
|
|
|
|
* the gfsec_secret_combine function. |
|
|
|
|
* |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if the secret can be reconstituted; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if improperly called (secret is NULL); |
|
|
|
|
* - GFSEC_ERR_INVALID_LENGTH if not all shares have the same length; |
|
|
|
|
* - GFSEC_ERR_NOT_ENOUGH_SHARES if not enough shares are available. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_can_combine(gfsec_secret_t *secret) |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
unsigned u, avail_shares; |
|
|
|
|
gfsec_share_t *share; |
|
|
|
|
|
|
|
|
@ -265,6 +414,21 @@ gfsec_secret_can_combine(gfsec_secret_t *secret)
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reconstitutes the secret. |
|
|
|
|
* The reconstituted secret will be stored in the data field of |
|
|
|
|
* the secret object. |
|
|
|
|
* |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if successful; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if called improperly (secret is NULL, |
|
|
|
|
* or gfsec_secret_can_recombine has not been called previously, |
|
|
|
|
* or it has been called but has found the secret could not be |
|
|
|
|
* reconstituted); |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if a memory allocation error occurs. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_combine(gfsec_secret_t *secret) |
|
|
|
|
{ |
|
|
|
@ -303,12 +467,16 @@ gfsec_secret_combine(gfsec_secret_t *secret)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gfshare_ctx_dec_extract(ctx, secret->data); |
|
|
|
|
gfshare_ctx_free(ctx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
/**
|
|
|
|
|
* Gets the number of partial shares in the secret object. |
|
|
|
|
*/ |
|
|
|
|
static unsigned |
|
|
|
|
gfsec_secret_get_partial_share_count(gfsec_secret_t *secret) |
|
|
|
|
{ |
|
|
|
|
unsigned u, n; |
|
|
|
@ -320,33 +488,29 @@ gfsec_secret_get_partial_share_count(gfsec_secret_t *secret)
|
|
|
|
|
return n; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
gfsec_secret_hash_shares(gfsec_secret_t *secret) |
|
|
|
|
{ |
|
|
|
|
gcry_md_hd_t md; |
|
|
|
|
gfsec_share_t *share; |
|
|
|
|
unsigned u; |
|
|
|
|
|
|
|
|
|
gcry_md_open(&md, GCRY_MD_SHA256, 0); |
|
|
|
|
|
|
|
|
|
for ( u = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
|
|
|
|
|
|
gcry_md_write(md, share->data, share->len); |
|
|
|
|
memcpy(share->hash, gcry_md_read(md, 0), 32); |
|
|
|
|
gcry_md_reset(md); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gcry_md_close(md); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Splits the secret and fills the shares accordingly. |
|
|
|
|
* |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* @param threshold The minimal number of shares needed to |
|
|
|
|
* reconstitute the secret. |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if successful; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if called improperly; |
|
|
|
|
* - GFSEC_ERR_NOT_ENOUGH_SHARES if the secret object does not define |
|
|
|
|
* enough shares to satisfy the desired threshold; |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if a memory allocation error occurs. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_split(gfsec_secret_t *secret, unsigned char threshold) |
|
|
|
|
{ |
|
|
|
|
gfshare_ctx *ctx; |
|
|
|
|
gcry_md_hd_t md; |
|
|
|
|
gfsec_share_t *share; |
|
|
|
|
unsigned char sharenrs[255]; |
|
|
|
|
unsigned u, v, n; |
|
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
if ( ! secret ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
@ -355,34 +519,69 @@ gfsec_secret_split(gfsec_secret_t *secret, unsigned char threshold)
|
|
|
|
|
if ( threshold >= n ) |
|
|
|
|
return GFSEC_ERR_NOT_ENOUGH_SHARES; |
|
|
|
|
|
|
|
|
|
for ( u = v = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
for ( u = v = rc = 0; u < secret->n_shares && rc == 0; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
|
if ( share->number != 0 ) |
|
|
|
|
|
|
|
|
|
if ( ! gfsec_share_is_full(share) ) |
|
|
|
|
sharenrs[v++] = share->number; |
|
|
|
|
|
|
|
|
|
if ( ! (share->data = malloc(secret->len)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( ! (share->hash = malloc(32)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( ! (share->data = malloc(32)) ) |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( ! (ctx = gfshare_ctx_init_enc(sharenrs, n, threshold, secret->len)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( rc == 0 && ! (ctx = gfshare_ctx_init_enc(sharenrs, n, threshold, |
|
|
|
|
secret->len)) ) |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
gfshare_ctx_enc_setsecret(ctx, secret->data); |
|
|
|
|
if ( rc == 0 && gcry_md_open(&md, GCRY_MD_SHA256, 0) != 0 ) |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
for ( u = v = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
|
if ( share->number != 0 ) |
|
|
|
|
gfshare_ctx_enc_getshare(ctx, v++, share->data); |
|
|
|
|
else |
|
|
|
|
memcpy(share->data, secret->data, secret->len); |
|
|
|
|
if ( rc == 0 ) { |
|
|
|
|
gfshare_ctx_enc_setsecret(ctx, secret->data); |
|
|
|
|
|
|
|
|
|
for ( u = v = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
|
|
|
|
|
|
if ( gfsec_share_is_full(share) ) |
|
|
|
|
gfshare_ctx_enc_getshare(ctx, v++, share->data); |
|
|
|
|
else |
|
|
|
|
memcpy(share->data, secret->data, secret->len); |
|
|
|
|
|
|
|
|
|
gcry_md_write(md, share->data, share->len); |
|
|
|
|
memcpy(share->hash, gcry_md_read(md, 0), 32); |
|
|
|
|
gcry_md_reset(md); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
for ( u = v = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
|
|
|
|
|
|
if ( share->data ) { |
|
|
|
|
free(share->data); |
|
|
|
|
share->data = NULL; |
|
|
|
|
} |
|
|
|
|
if ( share->hash ) { |
|
|
|
|
free(share->hash); |
|
|
|
|
share->hash = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gfshare_ctx_free(ctx); |
|
|
|
|
if ( ctx ) |
|
|
|
|
gfshare_ctx_free(ctx); |
|
|
|
|
if ( md ) |
|
|
|
|
gcry_md_close(md); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Frees a secret object and the associated shares. |
|
|
|
|
* |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
gfsec_secret_free(gfsec_secret_t *secret) |
|
|
|
|
{ |
|
|
|
@ -405,6 +604,14 @@ gfsec_secret_free(gfsec_secret_t *secret)
|
|
|
|
|
free(secret); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Translates a GFSEC_ERR_* error code into an error string. |
|
|
|
|
* |
|
|
|
|
* @param err The error code. |
|
|
|
|
* |
|
|
|
|
* @return A statically allocated string containing the error |
|
|
|
|
* message. |
|
|
|
|
*/ |
|
|
|
|
const char * |
|
|
|
|
gfsec_error_string(int err) |
|
|
|
|
{ |
|
|
|
|