1994-07-27 - Cryptosplit

Header Data

From: rjc@powermail.com (Ray)
To: cypherpunks@toad.com
Message Hash: 8d1d656815bb30f068147fd720ad58c56d8da9158d08dbf810abb1eb7d252795
Message ID: <199407271318.JAA01471@powermail.com>
Reply To: N/A
UTC Datetime: 1994-07-27 13:22:24 UTC
Raw Date: Wed, 27 Jul 94 06:22:24 PDT

Raw message

From: rjc@powermail.com (Ray)
Date: Wed, 27 Jul 94 06:22:24 PDT
To: cypherpunks@toad.com
Subject: Cryptosplit
Message-ID: <199407271318.JAA01471@powermail.com>
MIME-Version: 1.0
Content-Type: text/plain



  The recent postings about crypto sharing/spliting programs
renewed my interest, so I dusted off cryptosplit (a Shamir
secret sharing program I wrote around November of last year)
and fixed up the bugs which made it unusable. Here it is,
less bugged, about 10 times faster than before, but still ugly.


# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	README
#	Makefile
#	cryptosplit.c
#	gf.h
#
echo x - README
sed 's/^X//' >README << 'END-of-README'
X
XHow to use
X----------
XTo encode:
X
Xcsplit -g <number of pieces> -q <minimum number required for decode> [filename]
X
Xtake filename and split it into the number of pieces given by -g. Each
Xpiece is "filename.0", "filename.1", ..., "filename.(n-1)" if
Xfilename isn't supplied, it operates like kinda like a filter taking the
Xincoming data and spliting it into files "piece.0", "piece.1", ...
X
Xto decode:
X
Xprovide atleast the number of pieces specified by -q when you encoded.
XIf you specify less than the minimum number, it will not decode.
X
Xexample:
X
Xcsplit -g 5 -q 3 file
X[split file into 5 pieces, any 3 of which will reconstruct it]
X
Xcsplit file.0 file.1 file.2
X[put them together in the decoded file and output to stdout]
X
Xif you want to put it into a file, redirect it using the shell, or
Xuse "-o filename"
X
X-Ray
X
X
END-of-README
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X
XCFLAGS=-O
X
X
Xcsplit: cryptosplit.c gf.h
X	cc $(CFLAGS) cryptosplit.c -o csplit
X
END-of-Makefile
echo x - cryptosplit.c
sed 's/^X//' >cryptosplit.c << 'END-of-cryptosplit.c'
X/*
X * Cryptosplit 2.03 An implementation of Shamir secret sharing over GF(2^8)
X * 
X * written by Ray Cromwell <rjc@gnu.ai.mit.edu> Version 2.01 - fixed bug and
X * make it generate a different polynomial for each byte
X */
X
X/* Pay no attention to the sloppy code, this is only a first draft */
X
X#include "gf.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <stdio.h>
X
Xwrite_pieces(char **, char **, int);
Xwrite_key(char *, char *, int);
Xint             read_key(char *, int);
Xint             read_pieces(char **, int);
Xgenerate_key(char *);
X
Xint             quorum = 2;
Xint             pieces = 3;
X
Xint             generate = 0;
Xchar           *key = 0;
Xchar           *tmpkey = 0;
Xchar          **keypieces;
Xchar           *keyfiles[256];
Xchar           *outputfile = (char *) 0;
X
X#define CHUNKSIZE 8192
X#define RANDINIT(x) srand(time(0))
X#define RAND rand
X
Xmain(int argc, char *argv[])
X{
X	int             c = 1, k = 0;
X
X	RANDINIT(0);
X
X	if (argc == 1)
X		print_help();
X	keyfiles[0] = (char *) 0;
X
X	while (c < argc) {
X		if (argv[c][0] == '-') {
X			if (argv[c][1] == 'g') {
X				generate = 1;
X				c++;
X				if (c >= argc)
X					print_help();
X				pieces = atoi(argv[c++]);
X			} else if (argv[c][1] == 'q') {
X				c++;
X				if (c >= argc)
X					print_help();
X				quorum = atoi(argv[c++]);
X			} else if (argv[c][1] == 'o') {
X				c++;
X				if (c >= argc)
X					print_help();
X				outputfile = argv[c++];
X			}
X		} else {
X			keyfiles[k++] = argv[c++];
X		}
X	}
X	if (generate) {
X		if (k > 0) {
X			init_buffers();
X			if(quorum > pieces) pieces=quorum;
X			generate_keys(keyfiles[0]);
X		}
X	} else {
X		if (k < 2) {
X			fprintf(stderr, "You didn't supply enough pieces.\n");
X			exit(1);
X		}
X		quorum = pieces = k;
X		init_buffers();
X		rebuild_key(k);
X	}
X}
X
Xinit_buffers()
X{
X	int             i;
X	keypieces = (char **) malloc(sizeof(char *) * pieces);
X	for (i = 0; i < pieces; i++)
X		keypieces[i] = (char *) malloc(CHUNKSIZE);
X	key = (char *) malloc(CHUNKSIZE);
X	tmpkey = (char *) malloc(CHUNKSIZE);
X}
X
Xint 
Xread_pieces(char **files, int offset)
X{
X	int             i, s;
X	FILE           *f;
X	for (i = 0; i < quorum; i++) {
X		if (!(f = fopen(files[i], "r"))) {
X			perror("Cryptosplit");
X			exit(1);
X		}
X		fseek(f, offset, SEEK_SET);
X		if (feof(f)) {
X			fclose(f);
X			return 0;
X		}
X		s = fread(keypieces[i], 1, CHUNKSIZE, f);
X		fclose(f);
X	}
X	return s;
X}
X
Xrebuild_key(int ksize)
X{
X	unsigned char **coeffs;
X	unsigned char  *consts;
X	int             i, j, k, p, t, sr, ip, klen, off = 0;
X	unsigned char   x, y, z, r;
X	coeffs = (unsigned char **) malloc(sizeof(char *) * quorum);
X	t = 1;
X	x = 0;
X	for (i = 0; i < quorum; i++) {
X		coeffs[i] = (char *) malloc(quorum);
X	}
X	consts = (char *) malloc(quorum);
X	while (klen = read_pieces(keyfiles, off)) {
X		off += klen;
X		t = 1;
X		while (t < klen) {
X			for (i = 0; i < quorum; i++) {
X				x = keypieces[i][0];
X				y = keypieces[i][t];
X				consts[i] = y;
X				coeffs[i][quorum - 1] = 1;
X				z = x;
X				for (j = quorum - 2; j >= 0; j--) {
X					coeffs[i][j] = z;
X					z = GFMUL(z, x);
X				}
X			}
X			sr = 0;
X			ip = 0;
X/* Invert quorum x quorum matrix to obtain the constant factor */
X/* We can use lagrange interpolation or something better later.
X   Shamir says there is an O(n^2 log n) method, I'll code it when
X   I see it.                                                      */
X
X			for (i = sr; i < quorum; i++) {
X/*				print_matrix(coeffs, consts); */
X				r = GFINV(coeffs[i][i]);
X				consts[i] = GFMUL(consts[i], r);
X				coeffs[i][i] = 1;
X				for (j = sr + 1; j < quorum; j++) {
X					coeffs[i][j] = GFMUL(coeffs[i][j], r);
X				}
X				for (ip = i + 1; ip < quorum; ip++) {
X					r = coeffs[ip][sr];
X					for (j = sr; j < quorum; j++) {
X						z = GFMUL(coeffs[i][j], r);
X						coeffs[ip][j] = GFADD(coeffs[ip][j], GFMUL(coeffs[i][j], r));
X					}
X					consts[ip] = GFADD(consts[ip], GFMUL(consts[i], r));
X				}
X				sr = sr + 1;
X			}
X/*			print_matrix(coeffs, consts); */
X			key[t - 1] = consts[quorum - 1];
X			t++;
X		}
X		write_key(outputfile, key, klen - 1);
X	}
X}
X
Xint 
Xread_key(char *file, int offset)
X{
X	int             size;
X	FILE           *f;
X	if (file)
X		f = fopen(file, "r");
X	else
X		f = stdin;
X	fseek(f, offset, SEEK_SET);
X	if (feof(f)) {
X		fclose(f);
X		return 0;
X	}
X	size = fread(key, 1, CHUNKSIZE - 1, f);
X	fclose(f);
X	return size;
X}
X
Xint 
Xfilesize(char *file)
X{
X	struct stat     s;
X	if (stat(file, &s)) {
X		perror("Cryptosplit");
X		exit(0);
X	}
X	return s.st_size;
X}
X
Xgenerate_keys(char *keyfilename)
X{
X	int             i, j, k, o, keylength, off;
X	unsigned char  *coeffs;
X	unsigned char   x, y, z;
X	char            tmpname[256];
X	coeffs = (char *) malloc(sizeof(char *) * quorum);
X	off = 0;
X	if (!keyfilename)
X		keyfilename = "piece";
X
X	for (i = 0; i < pieces; i++) {
X		keyfiles[i] = (char *) malloc(256);
X		sprintf(keyfiles[i], "%s.%d", keyfilename, i);
X		unlink(keyfiles[i]);
X	}
X	while (keylength = read_key(keyfilename, off)) {
X		off += keylength;
X		for (j = 0; j < keylength; j++) {
X		  /* Generate a random quorum-1'th degree polynomial */
X			for (o = 1; o < quorum; o++) {
X				coeffs[o] = GF(RAND() % 256);
X			}
X			for (i = 0; i < pieces; i++) {
X				y = key[j];
X				x = GF(i + 1);
X				keypieces[i][0] = x;
X				z = x;
X				for (k = 1; k < quorum; k++) {
X					y = GFADD(y, GFMUL(coeffs[k], x));
X					x = GFMUL(x, z);
X				}
X				keypieces[i][j + 1] = y;
X			}
X		}
X		write_pieces(keyfiles, keypieces, keylength + 1);
X	}
X}
X
Xwrite_pieces(char **files, char **data, int ks)
X{
X	FILE           *f;
X	int             i;
X	for (i = 0; i < pieces; i++) {
X		f = fopen(files[i], "a");
X		fwrite(data[i], ks, 1, f);
X		fclose(f);
X	}
X}
X
Xwrite_key(char *file, char *t, int k)
X{
X	FILE           *f;
X	if (file)
X		f = fopen(file, "a");
X	else
X		f = stdout;
X	fwrite(t, k, 1, f);
X	fclose(f);
X}
X
Xprint_help()
X{
X	fprintf(stderr, "To generate 'pieces' of a 'key'\n");
X	fprintf(stderr, "Usage: cryptosplit -g <# of pieces> -q <quorum required to rebuild> keyfile\n\n");
X	fprintf(stderr, "To reconstruct the original file from n 'pieces'\n");
X	fprintf(stderr, "Usage: cryptosplit piece_1 piece_2 ... piece_n [-o output filename]\n");
X	exit(0);
X}
X
Xprint_matrix(char **co, char *c)
X{
X	int             i, j;
X	for (i = 0; i < quorum; i++) {
X		for (j = 0; j < quorum; j++) {
X			printf("%3u ", ((unsigned long) co[i][j] & 0xFF));
X		}
X		printf("= %3u\n", ((unsigned long) c[i] & 0xFF));
X	}
X	printf("\n");
X}
END-of-cryptosplit.c
echo x - gf.h
sed 's/^X//' >gf.h << 'END-of-gf.h'
X/* Cryptosplit
X * An implementation of Shamir secret sharing over GF(2^8)
X *
X * written by Ray Cromwell <rjc@gnu.ai.mit.edu>
X */
X
X/* Pay no attention to the sloppy code, this is only a first draft */
X
X/* g is a primitive element, this table represents g^k for 0 <= k <= 255 */
Xint G[]={
X1, 103, 129, 227, 78, 81, 222, 46, 50, 20, 176, 94, 170, 253, 166, 32, 
X33, 70, 199, 36, 106, 59, 229, 203, 249, 237, 93, 3, 169, 84, 242, 210, 
X243, 181, 114, 86, 60, 7, 226, 41, 208, 61, 96, 99, 202, 158, 108, 190, 
X77, 248, 138, 220, 224, 231, 5, 44, 252, 193, 161, 194, 8, 150, 250, 68, 
X9, 241, 123, 167, 71, 160, 165, 137, 117, 180, 21, 215, 223, 73, 179, 247, 
X254, 15, 116, 211, 148, 52, 145, 24, 109, 217, 204, 27, 196, 141, 62, 201, 
X55, 56, 76, 159, 11, 63, 174, 182, 219, 2, 206, 213, 17, 156, 162, 107, 
X92, 100, 40, 183, 188, 131, 45, 155, 64, 66, 140, 89, 72, 212, 118, 29, 
X65, 37, 13, 186, 6, 133, 168, 51, 115, 49, 189, 228, 172, 120, 14, 19, 
X82, 119, 122, 192, 198, 67, 235, 216, 171, 154, 39, 195, 111, 23, 25, 10, 
X88, 47, 85, 149, 83, 16, 251, 35, 136, 18, 53, 246, 153, 142, 151, 157, 
X197, 234, 191, 42, 121, 105, 146, 177, 57, 43, 30, 232, 113, 255, 104, 245, 
X48, 218, 101, 79, 54, 95, 205, 124, 69, 110, 112, 152, 233, 22, 126, 139, 
X187, 97, 4, 75, 125, 34, 239, 147, 214, 184, 200, 80, 185, 175, 209, 90, 
X225, 128, 132, 207, 178, 144, 127, 236, 58, 130, 74, 26, 163, 12, 221, 135, 
X102, 230, 98, 173, 31, 143, 240, 28, 38, 164, 238, 244, 87, 91, 134, 1, 
X};
X
X/* if n=g^k, this table returns k=lg n */
Xint I[]={
X0, 255, 105, 27, 210, 54, 132, 37, 60, 64, 159, 100, 237, 130, 142, 81, 
X165, 108, 169, 143, 9, 74, 205, 157, 87, 158, 235, 91, 247, 127, 186, 244, 
X15, 16, 213, 167, 19, 129, 248, 154, 114, 39, 179, 185, 55, 118, 7, 161, 
X192, 137, 8, 135, 85, 170, 196, 96, 97, 184, 232, 21, 36, 41, 94, 101, 
X120, 128, 121, 149, 63, 200, 17, 68, 124, 77, 234, 211, 98, 48, 4, 195, 
X219, 5, 144, 164, 29, 162, 35, 252, 160, 123, 223, 253, 112, 26, 11, 197, 
X42, 209, 242, 43, 113, 194, 240, 1, 190, 181, 20, 111, 46, 88, 201, 156, 
X202, 188, 34, 136, 82, 72, 126, 145, 141, 180, 146, 66, 199, 212, 206, 230, 
X225, 2, 233, 117, 226, 133, 254, 239, 168, 71, 50, 207, 122, 93, 173, 245, 
X229, 86, 182, 215, 84, 163, 61, 174, 203, 172, 153, 119, 109, 175, 45, 99, 
X69, 58, 110, 236, 249, 70, 14, 67, 134, 28, 12, 152, 140, 243, 102, 221, 
X10, 183, 228, 78, 73, 33, 103, 115, 217, 220, 131, 208, 116, 138, 47, 178, 
X147, 57, 59, 155, 92, 176, 148, 18, 218, 95, 44, 23, 90, 198, 106, 227, 
X40, 222, 31, 83, 125, 107, 216, 75, 151, 89, 193, 104, 51, 238, 6, 76, 
X52, 224, 38, 3, 139, 22, 241, 53, 187, 204, 177, 150, 231, 25, 250, 214, 
X246, 65, 30, 32, 251, 191, 171, 79, 49, 24, 62, 166, 56, 13, 80, 189, 
X};
X
X#define GFADD(a,b) ((a) ^ (b))
X#define GFMUL(a,b) (((a)==0 || (b)==0) ? 0 : G[(I[(a)] + I[(b)]) % 255])
X#define GFINV(a)   ((a)==0 ? 0 : G[255-I[(a)]])
X#define GF(a) (G[(a) % 255])
X#define LOGGF(a) (I[(a)%255])
X
END-of-gf.h
exit





Thread