#include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "rnd.h" #include "alg-util.h" #include "stdio-util.h" #include "priv-crypto.h" static int pp_ifd; static int pp_ofd; static int tio_saved; static struct termios tio_old; static struct termios tio_new; static void get_pp_fds(void) { pp_ifd = open("/dev/tty",O_RDWR,0); if (pp_ifd < 0) { pp_ifd = 0; pp_ofd = 1; } } static void save_tio(void) { tio_saved = (tcgetattr(pp_ifd,&tio_old) >= 0); } static void restore_tio(void) { tcsetattr(pp_ifd,TCSANOW,&tio_old); } static void echo_off(void) { if (tio_saved) { tio_new = tio_old; tio_new.c_lflag &= ~(ECHO|ECHOK|ECHOE|ECHOKE|ECHOPRT|ECHOCTL); if (tio_old.c_lflag & ECHO) tio_new.c_lflag |= ECHONL; tcsetattr(pp_ifd,TCSANOW,&tio_new); } } static void prompt(const char *, ...) __attribute__((__format__(__printf__,1,2))); static void prompt(const char *fmt, ...) { va_list ap; FILE *f; static int w(void *cookie __attribute__((__unused__)), const char *buf, int len) { return(write(pp_ofd,buf,len)); } f = fwopen(0,w); va_start(ap,fmt); vfprintf(f,fmt,ap); va_end(ap); fclose(f); } static void get_line(char **sp, int *sl) { FILE *f; int r; char c; f = fopen_alloc(sp,sl); while (1) { r = read(0,&c,1); switch (r) { case -1: switch (errno) { case EINTR: continue; break; default: fprintf(stderr,"%s: read: %s\n",__progname,strerror(errno)); exit(1); break; } break; case 0: fprintf(stderr,"%s: read EOF\n",__progname); break; case 1: break; default: fprintf(stderr,"%s: read returned %d?\n",__progname,r); exit(1); break; } if ((c == '\n') || (c == '\r')) { fclose(f); return; } putc(c,f); } } void priv_wrap(const void *in_d, int in_l, void **out_d, int *out_l, const char *pp) { int ppl; char *ppfree; void *h; unsigned char iv[8]; unsigned char *o; unsigned char *op; int ol; unsigned char hash[20]; unsigned char key[24]; const unsigned char *ip; int ill; unsigned char tmp[8]; if (! pp) { char *pp1; int pp1l; char *pp2; int pp2l; get_pp_fds(); save_tio(); echo_off(); while (1) { prompt("Enter a passphrase: "); get_line(&pp1,&pp1l); prompt("Enter the same passphrase again: "); get_line(&pp2,&pp2l); if ((pp1l == pp2l) && !bcmp(pp1,pp2,pp1l)) break; prompt("Mismatch. Try again.\n"); } restore_tio(); bzero(pp2,pp2l); free(pp2); pp = pp1; ppl = pp1l; ppfree = pp1; } else { ppl = strlen(pp); ppfree = 0; } if ((ppl == 0) || (in_l == 0)) { o = malloc(in_l+1); o[0] = 0; bcopy(in_d,o+1,in_l); *out_d = o; *out_l = in_l + 1; free(ppfree); return; } h = sha1_init(); sha1_process_bytes(h,pp,ppl); sha1_process_bytes(h,"A",1); sha1_result(h,&hash[0]); bcopy(&hash[0],&key[0],12); xor_block(&key[0],&hash[12],&key[0],8); h = sha1_init(); sha1_process_bytes(h,pp,ppl); sha1_process_bytes(h,"B",1); sha1_result(h,&hash[0]); bcopy(&hash[0],&key[12],12); xor_block(&key[12],&hash[12],&key[12],8); h = sha1_init(); sha1_process_bytes(h,&key[0],24); sha1_process_bytes(h,in_d,in_l); sha1_result(h,&hash[0]); xor_block(&hash[0],&hash[10],&hash[0],10); random_data(&iv[0],8); ol = 1 + in_l + 8 + 10; o = malloc(ol); op = o; *op++ = 1; ip = in_d; ill = in_l; while (ill >= 8) { bcopy(&iv[0],op,8); xor_block(&iv[0],ip,&tmp[0],8); des3(&iv[0],&tmp[0],&key[0],ENCRYPT); ip += 8; op += 8; ill -= 8; } if (ill) { bcopy(&iv[0],&tmp[0],8); xor_block(ip,&tmp[0],&tmp[0],ill); des3(&tmp[0],&tmp[0],&key[0],ENCRYPT); bcopy(&tmp[0],op,8); bcopy(&iv[0],op+8,ill); op += 8 + ill; } else { bcopy(&iv[0],op,8); op += 8; } bcopy(&hash[0],op,10); op += 10; if (op != o + ol) abort(); *out_d = o; *out_l = ol; bzero(&tmp[0],8); bzero(&iv[0],8); bzero(&key[0],24); bzero(&hash[0],20); free(ppfree); } int priv_unwrap(const void *in_d, int in_l, const char *comment, void **out_d, int *out_l, const char *pp) { static int try_unwrap(const char *pp, int ppl) { void *h; unsigned char hash[20]; unsigned char key[24]; unsigned char iv[8]; unsigned char tmp[8]; const unsigned char *ip; int ol; unsigned char *o; unsigned char *op; int ill; h = sha1_init(); sha1_process_bytes(h,pp,ppl); sha1_process_bytes(h,"A",1); sha1_result(h,&hash[0]); bcopy(&hash[0],&key[0],12); xor_block(&key[0],&hash[12],&key[0],8); h = sha1_init(); sha1_process_bytes(h,pp,ppl); sha1_process_bytes(h,"B",1); sha1_result(h,&hash[0]); bcopy(&hash[0],&key[12],12); xor_block(&key[12],&hash[12],&key[12],8); ip = ((const unsigned char *)in_d) + 1; ill = in_l - 1 - 8 - 10; ol = ill; o = malloc(ill); op = o; bcopy(ip,&iv[0],8); ip += 8; if (ill < 8) { des3(&tmp[0],&iv[0],&key[0],DECRYPT); xor_block(ip,&tmp[0],op,ill); op += ill; } else { ill -= 8; while (ill >= 8) { des3(&tmp[0],ip,&key[0],DECRYPT); xor_block(&iv[0],&tmp[0],op,8); bcopy(ip,&iv[0],8); ip += 8; op += 8; ill -= 8; } des3(&tmp[0],ip,&key[0],DECRYPT); ip += 8; if (ill == 0) { xor_block(&iv[0],&tmp[0],op,8); op += 8; } else { xor_block(ip,&tmp[0],op+8,ill); bcopy(ip,&tmp[0],ill); des3(&tmp[0],&tmp[0],&key[0],DECRYPT); xor_block(&iv[0],&tmp[0],op,8); op += ill + 8; ip += ill; } } if (op != o+ol) abort(); if (ip != ((const unsigned char *)in_d)+in_l-10) abort(); h = sha1_init(); sha1_process_bytes(h,&key[0],24); sha1_process_bytes(h,o,ol); sha1_result(h,&hash[0]); xor_block(&hash[0],&hash[10],&hash[0],10); if (bcmp(&hash[0],ip,10)) { bzero(o,ol); free(o); return(0); } *out_d = o; *out_l = ol; return(1); } if (in_l < 1) return(0); switch (*(const unsigned char *)in_d) { case 0: *out_l = in_l - 1; *out_d = malloc(in_l-1); bcopy(((const char *)in_d)+1,*out_d,in_l-1); return(1); break; case 1: break; default: return(0); break; } if (in_l < 8+1+10) return(0); if (! pp) { char *t; int l; get_pp_fds(); save_tio(); echo_off(); while (1) { prompt("Enter passphrase for key `%s': ",comment); get_line(&t,&l); if (l == 0) { free(t); return(0); } if (try_unwrap(t,l)) break; prompt("Wrong passphrase.\n"); bzero(t,l); free(t); } restore_tio(); bzero(t,l); free(t); return(1); } else { if (! try_unwrap(pp,strlen(pp))) { fprintf(stderr,"%s: wrong passphrase for this key\n",__progname); return(0); } return(1); } }