mirror of
https://github.com/AtHeartEngineer/sss.git
synced 2026-01-07 20:13:49 -05:00
152 lines
4.0 KiB
C
152 lines
4.0 KiB
C
/*
|
|
* AEAD wrapper around the Secret shared data
|
|
*
|
|
* Author: Daan Sprenkels <hello@dsprenkels.com>
|
|
*
|
|
* This module implements a AEAD wrapper around some secret shared data,
|
|
* allowing the data to be in any format. (Directly secret-sharing requires the
|
|
* message to be picked uniformly in the message space.)
|
|
*
|
|
* The NaCl cryptographic library is used for the encryption. The encryption
|
|
* scheme that is used for wrapping the message is salsa20/poly1305. Because
|
|
* we are using an ephemeral key, we are using a zero'd nonce.
|
|
*/
|
|
|
|
|
|
#include "randombytes.h"
|
|
#include "tweetnacl.h"
|
|
#include "sss.h"
|
|
#include "tweetnacl.h"
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
|
|
/*
|
|
* These assertions may be considered overkill, but would if the tweetnacl API
|
|
* ever change we *really* want to prevent buffer overflow vulnerabilities.
|
|
*/
|
|
#if crypto_secretbox_KEYBYTES != 32
|
|
# error "crypto_secretbox_KEYBYTES size is invalid"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Nonce for the `crypto_secretbox` authenticated encryption.
|
|
* The nonce is constant (zero), because we are using an ephemeral key.
|
|
*/
|
|
static const unsigned char nonce[crypto_secretbox_NONCEBYTES] = { 0 };
|
|
|
|
|
|
/*
|
|
* Return a mutable pointer to the ciphertext part of this Share
|
|
*/
|
|
static uint8_t* get_ciphertext(sss_Share *share)
|
|
{
|
|
return &((uint8_t*) share)[sss_KEYSHARE_LEN];
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a mutable pointer to the Keyshare part of this Share
|
|
*/
|
|
static sss_Keyshare* get_keyshare(sss_Share *share)
|
|
{
|
|
return (sss_Keyshare*) &share[0];
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a const pointer to the ciphertext part of this Share
|
|
*/
|
|
static const uint8_t* get_ciphertext_const(const sss_Share *share)
|
|
{
|
|
return &((const uint8_t*) share)[sss_KEYSHARE_LEN];
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a const pointer to the Keyshare part of this Share
|
|
*/
|
|
static const sss_Keyshare* get_keyshare_const(const sss_Share *share)
|
|
{
|
|
return (const sss_Keyshare*) &share[0];
|
|
}
|
|
|
|
|
|
/*
|
|
* Create `n` shares with theshold `k` and write them to `out`
|
|
*/
|
|
void sss_create_shares(sss_Share *out, const unsigned char *data,
|
|
uint8_t n, uint8_t k)
|
|
{
|
|
unsigned char key[32];
|
|
unsigned char m[crypto_secretbox_ZEROBYTES + sss_MLEN] = { 0 };
|
|
unsigned long long mlen = sizeof(m); /* length includes zero-bytes */
|
|
unsigned char c[mlen];
|
|
int tmp;
|
|
sss_Keyshare keyshares[n];
|
|
size_t idx;
|
|
|
|
/* Generate a random encryption key */
|
|
randombytes(key, sizeof(key));
|
|
|
|
/* AEAD encrypt the data with the key */
|
|
memcpy(&m[crypto_secretbox_ZEROBYTES], data, sss_MLEN);
|
|
tmp = crypto_secretbox(c, m, mlen, nonce, key);
|
|
assert(tmp == 0); /* should always happen */
|
|
|
|
/* Generate KeyShares */
|
|
sss_create_keyshares(keyshares, key, n, k);
|
|
|
|
/* Build regular shares */
|
|
for (idx = 0; idx < n; idx++) {
|
|
memcpy(get_keyshare((sss_Share*) &out[idx]), &keyshares[idx][0],
|
|
sss_KEYSHARE_LEN);
|
|
memcpy(get_ciphertext((sss_Share*) &out[idx]),
|
|
&c[crypto_secretbox_BOXZEROBYTES], sss_CLEN);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Combine `k` shares pointed to by `shares` and write the result to `data`
|
|
*
|
|
* This function returns -1 if any of the shares were corrupted or if the number
|
|
* of shares was too low. It is not possible to detect which of these errors
|
|
* did occur.
|
|
*/
|
|
int sss_combine_shares(uint8_t *data, const sss_Share *shares, uint8_t k)
|
|
{
|
|
unsigned char key[crypto_secretbox_KEYBYTES];
|
|
unsigned char c[crypto_secretbox_BOXZEROBYTES + sss_CLEN] = { 0 };
|
|
unsigned long long clen = sizeof(c);
|
|
unsigned char m[clen];
|
|
sss_Keyshare keyshares[k];
|
|
size_t idx;
|
|
int ret = 0;
|
|
|
|
/* Check if all ciphertexts are the same */
|
|
if (k < 1) return -1;
|
|
for (idx = 1; idx < k; idx++) {
|
|
if (memcmp(get_ciphertext_const(&shares[0]),
|
|
get_ciphertext_const(&shares[idx]), sss_CLEN) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Restore the key */
|
|
for (idx = 0; idx < k; idx++) {
|
|
memcpy(&keyshares[idx], get_keyshare_const(&shares[idx]),
|
|
sss_KEYSHARE_LEN);
|
|
}
|
|
sss_combine_keyshares(key, (const sss_Keyshare*) keyshares, k);
|
|
|
|
/* Decrypt the ciphertext */
|
|
memcpy(&c[crypto_secretbox_BOXZEROBYTES],
|
|
&shares[0][sss_KEYSHARE_LEN], sss_CLEN);
|
|
ret |= crypto_secretbox_open(m, c, clen, nonce, key);
|
|
memcpy(data, &m[crypto_secretbox_ZEROBYTES], sss_MLEN);
|
|
|
|
return ret;
|
|
}
|