/* This file is in the public domain. */ #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "rnd.h" #include "errf.h" #include "panic.h" #include "config.h" #include "nested.h" #include "interact.h" #include "alg-util.h" #include "stdio-util.h" #include "priv-crypto.h" 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; const char *pref; pref = ""; while (1) { get_with_prompt(&pp1,&pp1l,GWP_DEV_TTY|GWP_NO_ECHO,"%sEnter passphrase: ",pref); get_with_prompt(&pp2,&pp2l,GWP_DEV_TTY|GWP_NO_ECHO,"Enter the same passphrase again: "); if ((pp1l == pp2l) && !bcmp(pp1,pp2,pp1l)) break; pref = "Mismatch. Try again.\n"; bzero(pp1,pp1l); free(pp1); bzero(pp2,pp2l); free(pp2); } 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) panic("length mismatch"); *out_d = o; *out_l = ol; bzero(&tmp[0],8); bzero(&iv[0],8); bzero(&key[0],24); bzero(&hash[0],20); free(ppfree); } const char priv_unwrap__no_pp; int priv_unwrap(const void *in_d, int in_l, const char *comment, void **out_d, int *out_l, const char *pp) { NESTED 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) panic("length mismatch"); if (ip != ((const unsigned char *)in_d)+in_l-10) panic("block position wrong"); 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 (config_bool("no-interaction")) return(0); if (in_l < 8+1+10) return(0); if (! pp) { char *t; int l; const char *pref; pref = ""; while (1) { if (comment) { get_with_prompt(&t,&l,GWP_DEV_TTY|GWP_NO_ECHO,"%sEnter passphrase for key `%s': ",pref,comment); } else { get_with_prompt(&t,&l,GWP_DEV_TTY|GWP_NO_ECHO,"%sEnter passphrase: ",pref); } if (l == 0) { free(t); return(0); } if (try_unwrap(t,l)) break; pref = "Wrong passphrase.\n"; bzero(t,l); free(t); } bzero(t,l); free(t); return(1); } else if (pp == NO_PASSPHRASE) { return(0); } else { if (! try_unwrap(pp,strlen(pp))) { fprintf(errf,"%s: wrong passphrase for this key\n",__progname); return(0); } return(1); } } int priv_no_pp(const void *blob, int bloblen) { return((bloblen < 1) || (((const unsigned char *)blob)[0] == 0)); }