#include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #define MAX_PARTS 4096 static int sflag = 0; static int mflag = 0; static int iflag = 0; static int Iflag = 0; static int obase = 10; static int vflag = 0; #define VLEVEL(n) (vflag >= (n)) static int argc; static char **argv; static int rbits; static int rpool_n; static unsigned char *rpool; static int rpool_p; #define RPOOL_UNREVEALED 256 static void printv(int, const char *, ...) __attribute__ ((__format__(__printf__,2,3))); static void printv(int vlevel, const char *fmt, ...) { va_list ap; if (! VLEVEL(vlevel)) return; va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); } static void handleargs(int ac, char **av) { int errs; long int v; char *ep; errs = 0; argc = 0; argv = malloc((ac+1)*sizeof(char *)); for (ac--,av++;ac;ac--,av++) { if (**av == '-') { for (++*av;**av;++*av) { switch (**av) { default: fprintf(stderr,"%s: bad flag -%c\n",__progname,**av); errs ++; break; case 'm': mflag = 1; sflag = 0; break; case 's': sflag = 1; mflag = 0; break; case 'i': iflag = 1; break; case 'I': Iflag = 1; break; case 'v': vflag ++; break; case 'x': obase = 16; break; case 'b': ++ *av; v = strtol(*av,&ep,0); if (*ep || (ep == *av)) { fprintf(stderr,"%s: invalid number %s\n",__progname,*av); for (ep=*av;*ep;ep++) ; errs ++; } else { obase = v; } *av = ep - 1; break; } } } else { argv[argc++] = *av; } } if (errs) exit(1); } static void checkargs(void) { int errs; errs = 0; if (mflag) { if ((obase < 2) || (obase > 36)) { fprintf(stderr,"%s: output base must be [2..36]\n",__progname); errs ++; } if (argc < 2) { fprintf(stderr,"%s: need at least two parts with -m\n",__progname); errs ++; } } else if (sflag) { if (argc != 4) { fprintf(stderr,"%s: need exactly four args with -s\n",__progname); errs ++; } } else { fprintf(stderr,"%s: need either -s or -m\n",__progname); errs ++; } if (errs) exit(1); } static void random_stir(void) { void *mv; int o; unsigned char r[16]; int i; for (o=(rpool_n-1U)&~15U;o>=0;o-=16) { mv = md5_init(); md5_process_bytes(mv,rpool,rpool_n); md5_result(mv,&r[0]); for (i=0;i<16;i++) rpool[o+i] ^= r[i]; } } static void randomness_from_data(const void *buf, int nb) { const unsigned char *bp; bp = buf; for (;nb>0;nb--) { rpool[rpool_p++] ^= *bp++; if (rpool_p >= rpool_n) { random_stir(); rpool_p = RPOOL_UNREVEALED / 8; } } } static void randomness_from_fd(int fd) { char buf[8192]; int nb; while (1) { nb = read(fd,&buf[0],sizeof(buf)); randomness_from_data(&nb,sizeof(nb)); if (nb <= 0) break; randomness_from_data(&buf[0],nb); } } static void randomness_from_command(const char *execfile, ...) { int nargs; const char **args; const char *arg; va_list ap; int p[2]; int pid; const char *env[1]; va_start(ap,execfile); for (nargs=0;va_arg(ap,const char *);nargs++) ; va_end(ap); args = malloc((nargs+1)*sizeof(const char *)); va_start(ap,execfile); for (nargs=0;(arg=va_arg(ap,const char *));nargs++) args[nargs] = arg; va_end(ap); args[nargs] = 0; env[0] = 0; if (pipe(p) < 0) { fprintf(stderr,"%s: pipe: %s\n",__progname,strerror(errno)); exit(1); } pid = fork(); if (pid < 0) { fprintf(stderr,"%s: fork: %s\n",__progname,strerror(errno)); exit(1); } if (pid == 0) { if (p[1] != 1) { dup2(p[1],1); close(p[1]); } close(p[0]); execve(execfile,(const void *)args,(const void *)env); _exit(1); } close(p[1]); randomness_from_fd(p[0]); close(p[0]); while ((pid = wait3(0,WNOHANG,0)) > 0) ; } static void quick_randomness(void) { { struct timeval tv; gettimeofday(&tv,0); randomness_from_data(&tv,sizeof(tv)); } { struct rusage ru; getrusage(RUSAGE_SELF,&ru); randomness_from_data(&ru,sizeof(ru)); getrusage(RUSAGE_CHILDREN,&ru); randomness_from_data(&ru,sizeof(ru)); } { unsigned long int i; i = getpid(); randomness_from_data(&i,sizeof(i)); i = getppid(); randomness_from_data(&i,sizeof(i)); i = getuid(); randomness_from_data(&i,sizeof(i)); } } static void init_random(void) { printv(1,"Collecting randomness"); rpool_n = ((rbits + 127U + RPOOL_UNREVEALED) & ~127U) / 8U; rpool = malloc(rpool_n); rpool_p = 0; /* deliberately don't init it */ if (! Iflag) { printv(2,"\n (ps awwlxe)"); randomness_from_command("/bin/ps","ps","awwlxe",(char *)0); printv(2,"\n (w)"); randomness_from_command("/usr/bin/w","w",(char *)0); printv(2,"\n (ls -ali /tmp/.)"); randomness_from_command("/bin/ls","ls","-ali","/tmp/.",(char *)0); printv(2,"\n (netstat -s)"); randomness_from_command("/usr/bin/netstat","netstat","-s",(char *)0); printv(2,"\n (netstat -na)"); randomness_from_command("/usr/bin/netstat","netstat","-na",(char *)0); printv(2,"\n (netstat -ni)"); randomness_from_command("/usr/bin/netstat","netstat","-ni",(char *)0); } if (iflag || Iflag) { printv(2,"\n (stdin)"); randomness_from_fd(0); } printv(2,"\n (quick sources)"); quick_randomness(); printv(2,"\n (stirring)"); random_stir(); printv(1,"\n"); } static unsigned char random_byte(void) { unsigned char rv; rv = rpool[rpool_p++]; if (rpool_p >= rpool_n) { random_stir(); rpool_p = RPOOL_UNREVEALED / 8; } return(rv); } static void random_integer(MP_INT *num, unsigned int nbits) { unsigned int bytes; char *strform; int i; bytes = (nbits + 7) / 8; strform = malloc((bytes*2)+1); for (i=0;i 36)) { fprintf(stderr,"%s: invalid base in number %s\n",__progname,s); exit(1); } s = (*ep == ':') ? ep+1 : s0; } else { s = s0; } if (mpz_set_str(val,s,base) < 0) { fprintf(stderr,"%s: invalid number %s\n",__progname,s0); exit(1); } } static void compose_ints(MP_INT *rv, int n, ...) { int b; int bb; int bit; int j; int v; int any; va_list ap; mpz_set_ui(rv,0); bb = 0; b = 0; do { bit = 1 << b; any = 0; va_start(ap,n); for (j=0;j= bit) any = 1; if (v & bit) mpz_setbit(rv,bb); bb ++; } va_end(ap); b ++; } while (any); } static void decompose_ints(MP_INT *iv, int n, ...) { int bit; int i; int vn; int *vv; va_list ap; MP_INT t; vv = malloc(n*sizeof(int)); bzero(vv,n*sizeof(int)); mpz_init(&t); mpz_set(&t,iv); bit = 1; vn = 0; while (mpz_sgn(&t) > 0) { if (mpz_get_ui(&t) & 1) vv[vn] |= bit; mpz_tdiv_q_2exp(&t,&t,1); vn ++; if (vn >= n) { vn = 0; bit <<= 1; } } va_start(ap,n); for (i=0;i 0)) { fprintf(stderr,"%s: totalparts out of range [2..%d]\n",__progname,MAX_PARTS); exit(1); } totalparts = mpz_get_ui(&aux); get_arglist_number(&aux,argv[3]); if ((mpz_cmp_ui(&aux,2) <= 0) || (mpz_cmp_ui(&aux,totalparts) > 0)) { fprintf(stderr,"%s: minparts out of range [2..%d]\n",__progname,totalparts); exit(1); } minparts = mpz_get_ui(&aux); mpz_init(&secret); mpz_init(&modulus); get_arglist_number(&secret,argv[0]); get_arglist_number(&modulus,argv[1]); if (mpz_cmp(&secret,&modulus) >= 0) { fprintf(stderr,"%s: secret must be less than modulus\n",__progname); exit(1); } mbits = mpz_sizeinbase(&modulus,2); rbits = (minparts+1) * mbits; init_random(); printv(1,"Choosing polynomial coefficients\n"); coeffs = malloc(minparts*sizeof(MP_INT)); for (i=0;i cw[c]) cw[c] = w; } w = mpz_sizeinbase(&b[r],16); if (w > cw[nc]) cw[nc] = w; } for (r=0;r= 0) invalid_part(p,"part value out of range"); if (p == 0) { if ((tp < 2) || (tp > MAX_PARTS)) invalid_part(p,"total part count out of range [2..%d]",MAX_PARTS); totalparts = tp; if ((mp < 2) || (mp > tp)) invalid_part(p,"minimum part count out of range [2..%d]",totalparts); minparts = mp; mpz_set(&modulus,&aux2); mbits = mpz_sizeinbase(&modulus,2); pnos = malloc(argc*sizeof(int)); b = malloc(argc*sizeof(MP_INT)); for (i=0;i totalparts)) invalid_part(p,"impossible part number"); pnos[p] = pp; mpz_set(b+p,&aux1); } if (VLEVEL(1)) { fprintf(stderr,"modulus = "); mpz_out_str(stderr,16,&modulus); fprintf(stderr,"\n"); } for (p=1;p=0;i--) { if (pnos[p] == pnos[i]) { if (mpz_cmp(b+p,b+i) == 0) { fprintf(stderr,"%s: part %s repeated\n",__progname,argv[i]); } else { fprintf(stderr,"%s: parts %s and %s are inconsistent\n",__progname,argv[i],argv[p]); } exit(1); } } } if (argc < minparts) { fprintf(stderr,"%s: too few parts supplied, can't solve\n",__progname); exit(1); } m = malloc(argc*sizeof(MP_INT *)); m0 = malloc(argc*minparts*sizeof(MP_INT)); m[0] = m0; for (i=(argc*minparts)-1;i>=0;i--) mpz_init(&m[0][i]); for (i=1;i0;i--) { mpz_set(&m[p][i],&aux1); mpz_mul_ui(&aux1,&aux1,pnos[p]); mpz_mod(&aux1,&aux1,&modulus); } mpz_set(&m[p][0],&aux1); } printv(1,"Parts are superficially consistent, matrix set up.\n"); if (VLEVEL(2)) dumpmatrix(m,b,argc,minparts); /* At this point we need to solve M X = B (M is a matrix, X a column vector of the unknowns, and B a column vector of the knowns). Since we're in a finite field instead of the reals, any nonzero value will do equally well as a pivot. If we can't find _any_ pivot, something is wrong - this "can't happen", since we checked that the pnos[] values are all different and thus all the equations are known to be linearly inependent. We checked that argc >= minparts, and thus M has at least as many rows as columns. If more, we check that the extras are redundant... */ for (c=0;c= argc) panic("matrix is singular"); if (i != c) { MP_INT *tp; MP_INT tmi; printv(3,"Swapping rows %d and %d to obtain nonzero pivot\n",i,c); tp = m[i]; m[i] = m[c]; m[c] = tp; tmi = b[i]; b[i] = b[c]; b[c] = tmi; } mpz_gcdext(&aux2,&aux1,0,&m[c][c],&modulus); if (mpz_cmp_ui(&aux2,1) != 0) { fprintf(stderr,"%s: invalid split - modulus isn't prime: gcd(",__progname); mpz_out_str(stderr,10,&modulus); fprintf(stderr,","); mpz_out_str(stderr,10,&m[c][c]); fprintf(stderr,") = "); mpz_out_str(stderr,10,&aux2); fprintf(stderr,"\n"); exit(1); } mpz_mod(&aux1,&aux1,&modulus); if (VLEVEL(3)) { fprintf(stderr,"Pivot value is 0x"); mpz_out_str(stderr,16,&m[c][c]); fprintf(stderr,"\nReciprocal is 0x"); mpz_out_str(stderr,16,&aux1); fprintf(stderr,"\n"); } for (i=0;i