forked from dsprenkels/sss
-
Notifications
You must be signed in to change notification settings - Fork 1
/
sss.c
151 lines (125 loc) · 4.05 KB
/
sss.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
* 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;
}