2
* ssss version 0.4 - Copyright 2005 B. Poettering
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; either version 2 of the
7
* License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21
* http://point-at-infinity.org/ssss/
23
* This is an implementation of Shamir's Secret Sharing Scheme. See
24
* the project's homepage http://point-at-infinity.org/ssss/ for more
25
* information on this topic.
27
* This code links against the GNU multiprecision library "libgmp".
28
* I compiled the code successfully with gmp 4.1.4.
29
* You will need a system that has a /dev/random entropy source.
32
* "gcc -O2 -lgmp -o ssss-split ssss.c && ln ssss-split ssss-combine"
34
* Report bugs to: ssss AT point-at-infinity.org
49
#define RANDOM_SOURCE "/dev/random"
50
#define MAXDEGREE 1024
51
#define MAXTOKENLEN 128
52
#define MAXLINELEN (MAXTOKENLEN + 1 + 10 + 1 + MAXDEGREE / 4 + 10)
54
/* coefficients of some irreducible polynomials over GF(2) */
55
static const unsigned char irred_coeff[] = {
56
4,3,1,5,3,1,4,3,1,7,3,2,5,4,3,5,3,2,7,4,2,4,3,1,10,9,3,9,4,2,7,6,2,10,9,
57
6,4,3,1,5,4,3,4,3,1,7,2,1,5,3,2,7,4,2,6,3,2,5,3,2,15,3,2,11,3,2,9,8,7,7,
58
2,1,5,3,2,9,3,1,7,3,1,9,8,3,9,4,2,8,5,3,15,14,10,10,5,2,9,6,2,9,3,2,9,5,
59
2,11,10,1,7,3,2,11,2,1,9,7,4,4,3,1,8,3,1,7,4,1,7,2,1,13,11,6,5,3,2,7,3,2,
60
8,7,5,12,3,2,13,10,6,5,3,2,5,3,2,9,5,2,9,7,2,13,4,3,4,3,1,11,6,4,18,9,6,
61
19,18,13,11,3,2,15,9,6,4,3,1,16,5,2,15,14,6,8,5,2,15,11,2,11,6,2,7,5,3,8,
62
3,1,19,16,9,11,9,6,15,7,6,13,4,3,14,13,3,13,6,3,9,5,2,19,13,6,19,10,3,11,
63
6,5,9,2,1,14,3,2,13,3,1,7,5,4,11,9,8,11,6,5,23,16,9,19,14,6,23,10,2,8,3,
64
2,5,4,3,9,6,4,4,3,2,13,8,6,13,11,1,13,10,3,11,6,5,19,17,4,15,14,7,13,9,6,
65
9,7,3,9,7,1,14,3,2,11,8,2,11,6,4,13,5,2,11,5,1,11,4,1,19,10,3,21,10,6,13,
66
3,1,15,7,5,19,18,10,7,5,3,12,7,2,7,5,1,14,9,6,10,3,2,15,13,12,12,11,9,16,
67
9,7,12,9,3,9,5,2,17,10,6,24,9,3,17,15,13,5,4,3,19,17,8,15,6,3,19,6,1 };
69
int opt_showversion = 0;
74
int opt_diffusion = 1;
76
int opt_threshold = -1;
78
char *opt_token = NULL;
86
#define mpz_lshift(A, B, l) mpz_mul_2exp(A, B, l)
87
#define mpz_sizeinbits(A) (mpz_cmp_ui(A, 0) ? mpz_sizeinbase(A, 2) : 0)
91
fprintf(stderr, "%sFATAL: %s.\n", ttyoutput ? "\a" : "", msg);
95
void warning(char *msg)
98
fprintf(stderr, "%sWARNING: %s.\n", ttyoutput ? "\a" : "", msg);
101
/* field arithmetic routines */
103
int field_size_valid(int deg)
105
return (deg >= 8) && (deg <= MAXDEGREE) && (deg % 8 == 0);
108
/* initialize 'poly' to a bitfield representing the coefficients of an
109
irreducible polynomial of degree 'deg' */
111
void field_init(int deg)
113
mpz_init_set_ui(poly, 0);
114
mpz_setbit(poly, deg);
115
mpz_setbit(poly, irred_coeff[3 * (deg / 8 - 1) + 0]);
116
mpz_setbit(poly, irred_coeff[3 * (deg / 8 - 1) + 1]);
117
mpz_setbit(poly, irred_coeff[3 * (deg / 8 - 1) + 2]);
122
void field_deinit(void)
127
/* I/O routines for GF(2^deg) field elements */
129
void field_import(mpz_t x, const char *s, int hexmode)
132
if (strlen(s) > degree / 4)
133
fatal("input string too long");
134
if (strlen(s) < degree / 4)
135
warning("input string too short, adding null padding on the left");
136
if (mpz_set_str(x, s, 16) || (mpz_cmp_ui(x, 0) < 0))
137
fatal("invalid syntax");
142
if (strlen(s) > degree / 8)
143
fatal("input string too long");
144
for(i = strlen(s) - 1; i >= 0; i--)
145
warn = warn || (s[i] < 32) || (s[i] >= 127);
147
warning("binary data detected, use -x mode instead");
148
mpz_import(x, strlen(s), 1, 1, 0, 0, s);
152
void field_print(FILE* stream, const mpz_t x, int hexmode)
156
for(i = degree / 4 - mpz_sizeinbase(x, 16); i; i--)
157
fprintf(stream, "0");
158
mpz_out_str(stream, 16, x);
159
fprintf(stream, "\n");
162
char buf[MAXDEGREE / 8 + 1];
165
int printable, warn = 0;
166
memset(buf, degree / 8 + 1, 0);
167
mpz_export(buf, &t, 1, 1, 0, 0, x);
168
for(i = 0; i < t; i++) {
169
printable = (buf[i] >= 32) && (buf[i] < 127);
170
warn = warn || ! printable;
171
fprintf(stream, "%c", printable ? buf[i] : '.');
173
fprintf(stream, "\n");
175
warning("binary data detected, use -x mode instead");
179
/* basic field arithmetic in GF(2^deg) */
181
void field_add(mpz_t z, const mpz_t x, const mpz_t y)
186
void field_mult(mpz_t z, const mpz_t x, const mpz_t y)
192
if (mpz_tstbit(y, 0))
196
for(i = 1; i < degree; i++) {
198
if (mpz_tstbit(b, degree))
200
if (mpz_tstbit(y, i))
206
void field_invert(mpz_t z, const mpz_t x)
210
assert(mpz_cmp_ui(x, 0));
212
mpz_init_set(v, poly);
213
mpz_init_set_ui(g, 0);
216
while (mpz_cmp_ui(u, 1)) {
217
i = mpz_sizeinbits(u) - mpz_sizeinbits(v);
228
mpz_clear(u); mpz_clear(v); mpz_clear(g); mpz_clear(h);
231
/* routines for the random number generator */
233
void cprng_init(void)
235
if ((cprng = open(RANDOM_SOURCE, O_RDONLY)) < 0)
236
fatal("couldn't open " RANDOM_SOURCE);
239
void cprng_deinit(void)
241
if (close(cprng) < 0)
242
fatal("couldn't close " RANDOM_SOURCE);
245
void cprng_read(mpz_t x)
247
char buf[MAXDEGREE / 8];
250
for(count = 0; count < degree / 8; count += i)
251
if ((i = read(cprng, buf + count, degree / 8 - count)) < 0) {
253
fatal("couldn't read from " RANDOM_SOURCE);
255
mpz_import(x, degree / 8, 1, 1, 0, 0, buf);
258
/* a 64 bit pseudo random permutation (based on the XTEA cipher) */
260
void encipher_block(uint32_t *v)
262
uint32_t sum = 0, delta = 0x9E3779B9;
264
for(i = 0; i < 32; i++) {
265
v[0] += (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ sum;
267
v[1] += (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ sum;
271
void decipher_block(uint32_t *v)
273
uint32_t sum = 0xC6EF3720, delta = 0x9E3779B9;
275
for(i = 0; i < 32; i++) {
276
v[1] -= ((v[0] << 4 ^ v[0] >> 5) + v[0]) ^ sum;
278
v[0] -= ((v[1] << 4 ^ v[1] >> 5) + v[1]) ^ sum;
282
void encode_slice(uint8_t *data, int idx, int len,
283
void (*process_block)(uint32_t*))
287
for(i = 0; i < 2; i++)
288
v[i] = data[(idx + 4 * i) % len] << 24 |
289
data[(idx + 4 * i + 1) % len] << 16 |
290
data[(idx + 4 * i + 2) % len] << 8 | data[(idx + 4 * i + 3) % len];
292
for(i = 0; i < 2; i++) {
293
data[(idx + 4 * i + 0) % len] = v[i] >> 24;
294
data[(idx + 4 * i + 1) % len] = (v[i] >> 16) & 0xff;
295
data[(idx + 4 * i + 2) % len] = (v[i] >> 8) & 0xff;
296
data[(idx + 4 * i + 3) % len] = v[i] & 0xff;
300
enum encdec {ENCODE, DECODE};
302
void encode_mpz(mpz_t x, enum encdec encdecmode)
304
uint8_t v[(MAXDEGREE + 8) / 16 * 2];
307
memset(v, 0, (degree + 8) / 16 * 2);
308
mpz_export(v, &t, -1, 2, 1, 0, x);
309
if (degree % 16 == 8)
310
v[degree / 8 - 1] = v[degree / 8];
311
if (encdecmode == ENCODE) /* 40 rounds are more than enough!*/
312
for(i = 0; i < 40 * ((int)degree / 8); i += 2)
313
encode_slice(v, i, degree / 8, encipher_block);
315
for(i = 40 * (degree / 8) - 2; i >= 0; i -= 2)
316
encode_slice(v, i, degree / 8, decipher_block);
317
if (degree % 16 == 8) {
318
v[degree / 8] = v[degree / 8 - 1];
319
v[degree / 8 - 1] = 0;
321
mpz_import(x, (degree + 8) / 16, -1, 2, 1, 0, v);
322
assert(mpz_sizeinbits(x) <= degree);
325
/* evaluate polynomials efficiently */
327
void horner(int n, mpz_t y, const mpz_t x, const mpz_t coeff[])
331
for(i = n - 1; i; i--) {
332
field_add(y, y, coeff[i]);
335
field_add(y, y, coeff[0]);
338
/* calculate the secret from a set of shares solving a linear equation system */
340
#define MPZ_SWAP(A, B) \
341
do { mpz_set(h, A); mpz_set(A, B); mpz_set(B, h); } while(0)
343
int restore_secret(int n, mpz_t (*A)[n], mpz_t b[])
345
mpz_t (*AA)[n] = (mpz_t (*)[n])A;
349
for(i = 0; i < n; i++) {
350
if (! mpz_cmp_ui(AA[i][i], 0)) {
351
for(found = 0, j = i + 1; j < n; j++)
352
if (mpz_cmp_ui(AA[i][j], 0)) {
358
for(k = i; k < n; k++)
359
MPZ_SWAP(AA[k][i], AA[k][j]);
360
MPZ_SWAP(b[i], b[j]);
362
for(j = i + 1; j < n; j++) {
363
if (mpz_cmp_ui(AA[i][j], 0)) {
364
for(k = i + 1; k < n; k++) {
365
field_mult(h, AA[k][i], AA[i][j]);
366
field_mult(AA[k][j], AA[k][j], AA[i][i]);
367
field_add(AA[k][j], AA[k][j], h);
369
field_mult(h, b[i], AA[i][j]);
370
field_mult(b[j], b[j], AA[i][i]);
371
field_add(b[j], b[j], h);
375
field_invert(h, AA[n - 1][n - 1]);
376
field_mult(b[n - 1], b[n - 1], h);
381
/* Prompt for a secret, generate shares for it */
385
unsigned int fmt_len;
386
mpz_t x, y, coeff[opt_threshold];
387
char buf[MAXLINELEN];
389
for(fmt_len = 1, i = opt_number; i >= 10; i /= 10, fmt_len++);
391
printf("Generating shares using a (%d,%d) scheme with ",
392
opt_threshold, opt_number);
394
printf("a %d bit", opt_security);
397
printf(" security level.\n");
399
int deg = opt_security ? opt_security : MAXDEGREE;
400
fprintf(stderr, "Enter the secret, ");
402
fprintf(stderr, "as most %d hex digits: ", deg / 4);
404
fprintf(stderr, "at most %d ASCII characters: ", deg / 8);
406
if (! fgets(buf, sizeof(buf), stdin))
407
fatal("I/O error while reading secret");
408
buf[strcspn(buf, "\r\n")] = '\0';
410
if (! opt_security) {
411
opt_security = opt_hex ? 4 * ((strlen(buf) + 1) & ~1): 8 * strlen(buf);
414
fprintf(stderr, "Using a %d bit security level.\n", opt_security);
416
field_init(opt_security);
419
field_import(coeff[0], buf, opt_hex);
423
encode_mpz(coeff[0], ENCODE);
425
warning("security level too small for the diffusion layer");
429
for(i = 1; i < opt_threshold; i++) {
431
cprng_read(coeff[i]);
437
for(i = 0; i < opt_number; i++) {
438
mpz_set_ui(x, i + 1);
439
horner(opt_threshold, y, x, (const mpz_t*)coeff);
441
printf("%s-", opt_token);
442
printf("%0*d-", fmt_len, i + 1);
443
field_print(stdout, y, 1);
448
for(i = 0; i < opt_threshold; i++)
453
/* Prompt for shares, calculate the secret */
457
mpz_t A[opt_threshold][opt_threshold], y[opt_threshold], x;
458
char buf[MAXLINELEN];
465
printf("Enter %d shares separated by newlines:\n", opt_threshold);
466
for (i = 0; i < opt_threshold; i++) {
468
printf("Share [%d/%d]: ", i + 1, opt_threshold);
470
if (! fgets(buf, sizeof(buf), stdin))
471
fatal("I/O error while reading shares");
472
buf[strcspn(buf, "\r\n")] = '\0';
473
if (! (a = strchr(buf, '-')))
474
fatal("invalid syntax");
476
if ((b = strchr(a, '-')))
483
if (! field_size_valid(s))
484
fatal("share has illegal length");
488
if (s != 4 * strlen(b))
489
fatal("shares have different security levels");
492
fatal("invalid share");
494
mpz_init_set_ui(A[opt_threshold - 1][i], 1);
495
for(j = opt_threshold - 2; j >= 0; j--) {
497
field_mult(A[j][i], A[j + 1][i], x);
500
field_import(y[i], b, 1);
501
field_mult(x, x, A[0][i]);
502
field_add(y[i], y[i], x);
505
if (restore_secret(opt_threshold, A, y))
506
fatal("shares inconsistent. Perhaps a single share was used twice");
510
encode_mpz(y[opt_threshold - 1], DECODE);
512
warning("security level too small for the diffusion layer");
516
fprintf(stderr, "Resulting secret: ");
517
field_print(stderr, y[opt_threshold - 1], opt_hex);
519
for (i = 0; i < opt_threshold; i++) {
520
for (j = 0; j < opt_threshold; j++)
527
int main(int argc, char *argv[])
531
if ((i = fileno(stderr)) < 0)
532
fatal("couldn't determine fileno of stderr");
533
ttyoutput = isatty(i);
535
opt_help = argc == 1;
536
while((i = getopt(argc, argv, "vDhqQxs:t:n:w:")) != -1)
538
case 'v': opt_showversion = 1; break;
539
case 'h': opt_help = 1; break;
540
case 'q': opt_quiet = 1; break;
541
case 'Q': opt_QUIET = opt_quiet = 1; break;
542
case 'x': opt_hex = 1; break;
543
case 's': opt_security = atoi(optarg); break;
544
case 't': opt_threshold = atoi(optarg); break;
545
case 'n': opt_number = atoi(optarg); break;
546
case 'w': opt_token = optarg; break;
547
case 'D': opt_diffusion = 0; break;
551
if (! opt_help && (argc != optind))
552
fatal("invalid argument");
554
if ((name = strrchr(argv[0], '/')) == NULL)
557
if (strstr(name, "split")) {
558
if (opt_help || opt_showversion) {
559
puts("Split secrets using Shamir's Secret Sharing Scheme.\n"
561
"ssss-split -t threshold -n shares [-w token] [-s level]"
562
" [-x] [-q] [-Q] [-D] [-v]"
565
puts("\nVersion: " VERSION);
569
if (opt_threshold < 2)
570
fatal("invalid parameters: invalid threshold value");
572
if (opt_number < opt_threshold)
573
fatal("invalid parameters: number of shares smaller than threshold");
575
if (opt_security && ! field_size_valid(opt_security))
576
fatal("invalid parameters: invalid security level");
578
if (opt_token && (strlen(opt_token) > MAXTOKENLEN))
579
fatal("invalid parameters: token too long");
584
if (opt_help || opt_showversion) {
585
puts("Combine shares using Shamir's Secret Sharing Scheme.\n"
587
"ssss-combine -t threshold [-x] [-q] [-Q] [-D] [-v]");
589
puts("\nVersion: " VERSION);
593
if (opt_threshold < 2)
594
fatal("invalid parameters: invalid threshold value");