137da2899SCharles.Forsythimplement Crypt; 237da2899SCharles.Forsyth 337da2899SCharles.Forsyth# encrypt/decrypt from stdin to stdout 437da2899SCharles.Forsyth 537da2899SCharles.Forsythinclude "sys.m"; 637da2899SCharles.Forsyth sys: Sys; 737da2899SCharles.Forsyth stderr: ref Sys->FD; 837da2899SCharles.Forsythinclude "draw.m"; 937da2899SCharles.Forsythinclude "keyring.m"; 1037da2899SCharles.Forsyth keyring: Keyring; 1137da2899SCharles.Forsythinclude "security.m"; 1237da2899SCharles.Forsyth ssl: SSL; 13*66f5808bSforsythinclude "bufio.m"; 14*66f5808bSforsythinclude "msgio.m"; 15*66f5808bSforsyth msgio: Msgio; 1637da2899SCharles.Forsythinclude "arg.m"; 1737da2899SCharles.Forsyth 1837da2899SCharles.ForsythCrypt: module { 1937da2899SCharles.Forsyth init: fn(nil: ref Draw->Context, argv: list of string); 2037da2899SCharles.Forsyth}; 2137da2899SCharles.Forsyth 2237da2899SCharles.ForsythEhungup: con "i/o on hungup channel"; 2337da2899SCharles.Forsyth 2437da2899SCharles.ForsythALGSTR: con "alg "; 2537da2899SCharles.ForsythDEFAULTALG: con "md5/ideacbc"; 2637da2899SCharles.Forsythusage() 2737da2899SCharles.Forsyth{ 2837da2899SCharles.Forsyth sys->fprint(stderr, "usage: crypt [-?] [-d] [-k secret] [-f secretfile] [-a alg[/alg]]\n"); 2937da2899SCharles.Forsyth sys->fprint(stderr, "available algorithms:\n"); 3037da2899SCharles.Forsyth showalgs(stderr); 3137da2899SCharles.Forsyth fail("bad usage"); 3237da2899SCharles.Forsyth} 3337da2899SCharles.Forsyth 3437da2899SCharles.Forsythbadmodule(m: string) 3537da2899SCharles.Forsyth{ 3637da2899SCharles.Forsyth sys->fprint(stderr, "crypt: cannot load %s: %r\n", m); 3737da2899SCharles.Forsyth fail("bad module"); 3837da2899SCharles.Forsyth} 3937da2899SCharles.Forsyth 4037da2899SCharles.Forsythheaders: con 1; 4137da2899SCharles.Forsythverbose := 0; 4237da2899SCharles.Forsyth 4337da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string) 4437da2899SCharles.Forsyth{ 4537da2899SCharles.Forsyth sys = load Sys Sys->PATH; 4637da2899SCharles.Forsyth stderr = sys->fildes(2); 4737da2899SCharles.Forsyth ssl = load SSL SSL->PATH; 4837da2899SCharles.Forsyth if (ssl == nil) 4937da2899SCharles.Forsyth badmodule(SSL->PATH); 5037da2899SCharles.Forsyth keyring = load Keyring Keyring->PATH; 5137da2899SCharles.Forsyth if (keyring == nil) 5237da2899SCharles.Forsyth badmodule(SSL->PATH); 53*66f5808bSforsyth msgio = load Msgio Msgio->PATH; 54*66f5808bSforsyth msgio->init(); 5537da2899SCharles.Forsyth 5637da2899SCharles.Forsyth arg := load Arg Arg->PATH; 5737da2899SCharles.Forsyth if (arg == nil) 5837da2899SCharles.Forsyth badmodule(SSL->PATH); 5937da2899SCharles.Forsyth 6037da2899SCharles.Forsyth decrypt := 0; 6137da2899SCharles.Forsyth secret: array of byte; 6237da2899SCharles.Forsyth alg := DEFAULTALG; 6337da2899SCharles.Forsyth 6437da2899SCharles.Forsyth arg->init(argv); 6537da2899SCharles.Forsyth while ((opt := arg->opt()) != 0) { 6637da2899SCharles.Forsyth case opt { 6737da2899SCharles.Forsyth 'd' => 6837da2899SCharles.Forsyth decrypt = 1; 6937da2899SCharles.Forsyth 'k' => 7037da2899SCharles.Forsyth if ((s := arg->arg()) == nil) 7137da2899SCharles.Forsyth usage(); 7237da2899SCharles.Forsyth secret = array of byte s; 7337da2899SCharles.Forsyth 'f' => 7437da2899SCharles.Forsyth if ((f := arg->arg()) == nil) 7537da2899SCharles.Forsyth usage(); 7637da2899SCharles.Forsyth secret = readfile(f); 7737da2899SCharles.Forsyth 'a' => 7837da2899SCharles.Forsyth if ((alg = arg->arg()) == nil) 7937da2899SCharles.Forsyth usage(); 8037da2899SCharles.Forsyth '?' => 8137da2899SCharles.Forsyth showalgs(sys->fildes(1)); 8237da2899SCharles.Forsyth return; 8337da2899SCharles.Forsyth 'v' => 8437da2899SCharles.Forsyth verbose = 1; 8537da2899SCharles.Forsyth * => 8637da2899SCharles.Forsyth usage(); 8737da2899SCharles.Forsyth } 8837da2899SCharles.Forsyth } 8937da2899SCharles.Forsyth argv = arg->argv(); 9037da2899SCharles.Forsyth if (argv != nil) 9137da2899SCharles.Forsyth usage(); 92*66f5808bSforsyth if(secret == nil) 93*66f5808bSforsyth secret = array of byte readpassword(); 9437da2899SCharles.Forsyth sk := array[Keyring->SHA1dlen] of byte; 9537da2899SCharles.Forsyth keyring->sha1(secret, len secret, sk, nil); 9637da2899SCharles.Forsyth if (headers) { 9737da2899SCharles.Forsyth # deal with header - the header encodes the algorithm along with the data. 9837da2899SCharles.Forsyth if (decrypt) { 99*66f5808bSforsyth msg := msgio->getmsg(sys->fildes(0)); 10037da2899SCharles.Forsyth if (msg != nil) 10137da2899SCharles.Forsyth alg = string msg; 10237da2899SCharles.Forsyth if (msg == nil || len alg < len ALGSTR || alg[0:len ALGSTR] != ALGSTR) 10337da2899SCharles.Forsyth error("couldn't get decrypt algorithm"); 10437da2899SCharles.Forsyth alg = alg[len ALGSTR:]; 10537da2899SCharles.Forsyth } else { 10637da2899SCharles.Forsyth msg := array of byte ("alg " + alg); 107*66f5808bSforsyth e := msgio->sendmsg(sys->fildes(1), msg, len msg); 10837da2899SCharles.Forsyth if (e == -1) 10937da2899SCharles.Forsyth error("couldn't write algorithm string"); 11037da2899SCharles.Forsyth } 11137da2899SCharles.Forsyth } 11237da2899SCharles.Forsyth fd := docrypt(decrypt, alg, sk); 11337da2899SCharles.Forsyth if (decrypt) { 11437da2899SCharles.Forsyth # if decrypting, don't use stream, as we want to catch 11537da2899SCharles.Forsyth # decryption or checksum errors when they happen. 11637da2899SCharles.Forsyth buf := array[Sys->ATOMICIO] of byte; 11737da2899SCharles.Forsyth stdout := sys->fildes(1); 11837da2899SCharles.Forsyth while ((n := sys->read(fd, buf, len buf)) > 0) 11937da2899SCharles.Forsyth sys->write(stdout, buf, n); 12037da2899SCharles.Forsyth 12137da2899SCharles.Forsyth if (n == -1) { 12237da2899SCharles.Forsyth err := sys->sprint("%r"); 12337da2899SCharles.Forsyth if (err != Ehungup) 12437da2899SCharles.Forsyth error("decryption failed: " + err); 12537da2899SCharles.Forsyth } 12637da2899SCharles.Forsyth } else { 12737da2899SCharles.Forsyth stream(fd, sys->fildes(1), Sys->ATOMICIO); 12837da2899SCharles.Forsyth } 12937da2899SCharles.Forsyth} 13037da2899SCharles.Forsyth 13137da2899SCharles.Forsythdocrypt(decrypt: int, alg: string, sk: array of byte): ref Sys->FD 13237da2899SCharles.Forsyth{ 13337da2899SCharles.Forsyth if (verbose) 13437da2899SCharles.Forsyth sys->fprint(stderr, "%scrypting with alg %s\n", (array[] of {"en", "de"})[decrypt!=0], alg); 13537da2899SCharles.Forsyth (err, fds, nil, nil) := cryptpipe(decrypt, alg, sk); 13637da2899SCharles.Forsyth if (err != nil) 13737da2899SCharles.Forsyth error(err); 13837da2899SCharles.Forsyth 13937da2899SCharles.Forsyth spawn stream(sys->fildes(0), fds[1], Sys->ATOMICIO); 14037da2899SCharles.Forsyth return fds[0]; 14137da2899SCharles.Forsyth} 14237da2899SCharles.Forsyth 14337da2899SCharles.Forsyth# set up an encrypt/decrypt session; if decrypt is non-zero, then 14437da2899SCharles.Forsyth# decrypt, else encrypt. alg is the algorithm to use; sk is the 14537da2899SCharles.Forsyth# used as the secret key. 14637da2899SCharles.Forsyth# returns tuple (err, fds, cfd, dir) 14737da2899SCharles.Forsyth# where err is non-nil on failure; 14837da2899SCharles.Forsyth# otherwise fds is an array of two fds; writing to fds[1] will make 14937da2899SCharles.Forsyth# crypted/decrypted data available to be read on fds[0]. 15037da2899SCharles.Forsyth# dir is the ssl directory in question. 15137da2899SCharles.Forsythcryptpipe(decrypt: int, alg: string, sk: array of byte): (string, array of ref Sys->FD, ref Sys->FD, string) 15237da2899SCharles.Forsyth{ 15337da2899SCharles.Forsyth pfd := array[2] of ref Sys->FD; 15437da2899SCharles.Forsyth if (sys->pipe(pfd) == -1) 15537da2899SCharles.Forsyth return ("pipe failed", nil, nil, nil); 15637da2899SCharles.Forsyth 15737da2899SCharles.Forsyth (err, c) := ssl->connect(pfd[1]); 15837da2899SCharles.Forsyth if (err != nil) 159a6011949SCharles.Forsyth return ("could not connect ssl: "+err, nil, nil, nil); 16037da2899SCharles.Forsyth pfd[1] = nil; 16137da2899SCharles.Forsyth err = ssl->secret(c, sk, sk); 16237da2899SCharles.Forsyth if (err != nil) 163a6011949SCharles.Forsyth return ("could not write secret: "+err, nil, nil, nil); 16437da2899SCharles.Forsyth 16537da2899SCharles.Forsyth if (alg != nil) 16637da2899SCharles.Forsyth if (sys->fprint(c.cfd, "alg %s", alg) == -1) 16737da2899SCharles.Forsyth return (sys->sprint("bad algorithm %s: %r", alg), nil, nil, nil); 16837da2899SCharles.Forsyth 16937da2899SCharles.Forsyth fds := array[2] of ref Sys->FD; 17037da2899SCharles.Forsyth if (decrypt) { 17137da2899SCharles.Forsyth fds[1] = pfd[0]; 17237da2899SCharles.Forsyth fds[0] = c.dfd; 17337da2899SCharles.Forsyth } else { 17437da2899SCharles.Forsyth fds[1] = c.dfd; 17537da2899SCharles.Forsyth fds[0] = pfd[0]; 17637da2899SCharles.Forsyth } 17737da2899SCharles.Forsyth return (nil, fds, c.cfd, c.dir); 17837da2899SCharles.Forsyth} 17937da2899SCharles.Forsyth 18037da2899SCharles.Forsythalgnames := array[] of {("crypt", "encalgs"), ("hash", "hashalgs")}; 18137da2899SCharles.Forsyth 18237da2899SCharles.Forsyth# find available algorithms and return as tuple of two lists: 18337da2899SCharles.Forsyth# (err, hashalgs, cryptalgs) 18437da2899SCharles.Forsythalgs(): (string, array of list of string) 18537da2899SCharles.Forsyth{ 18637da2899SCharles.Forsyth (err, nil, nil, dir) := cryptpipe(0, nil, array[100] of byte); 18737da2899SCharles.Forsyth if (err != nil) 18837da2899SCharles.Forsyth return (err, nil); 18937da2899SCharles.Forsyth alglists := array[len algnames] of list of string; 19037da2899SCharles.Forsyth for (i := 0; i < len algnames; i++) { 19137da2899SCharles.Forsyth (nil, f) := algnames[i]; 19237da2899SCharles.Forsyth (nil, alglists[i]) = sys->tokenize(string readfile(dir + "/" + f), " "); 19337da2899SCharles.Forsyth } 19437da2899SCharles.Forsyth return (nil, alglists); 19537da2899SCharles.Forsyth} 19637da2899SCharles.Forsyth 19737da2899SCharles.Forsythshowalgs(fd: ref Sys->FD) 19837da2899SCharles.Forsyth{ 19937da2899SCharles.Forsyth (err, alglists) := algs(); 20037da2899SCharles.Forsyth if (err != nil) 20137da2899SCharles.Forsyth error("cannot get algorithms: " + err); 20237da2899SCharles.Forsyth for (j := 0; j < len alglists; j++) { 20337da2899SCharles.Forsyth (name, nil) := algnames[j]; 20437da2899SCharles.Forsyth sys->fprint(fd, "%s:", name); 20537da2899SCharles.Forsyth for (l := alglists[j]; l != nil; l = tl l) 20637da2899SCharles.Forsyth sys->fprint(fd, " %s", hd l); 20737da2899SCharles.Forsyth sys->fprint(fd, "\n"); 20837da2899SCharles.Forsyth } 20937da2899SCharles.Forsyth} 21037da2899SCharles.Forsyth 211*66f5808bSforsythreadpassword(): string 212*66f5808bSforsyth{ 213*66f5808bSforsyth bufio := load Bufio Bufio->PATH; 214*66f5808bSforsyth Iobuf: import bufio; 215*66f5808bSforsyth stdin := bufio->open("/dev/cons", Sys->OREAD); 216*66f5808bSforsyth 217*66f5808bSforsyth cfd := sys->open("/dev/consctl", Sys->OWRITE); 218*66f5808bSforsyth if (cfd == nil || sys->fprint(cfd, "rawon") <= 0) 219*66f5808bSforsyth sys->fprint(stderr, "crypt: warning: cannot hide typed password\n"); 220*66f5808bSforsyth sys->fprint(stderr, "password: "); 221*66f5808bSforsyth s := ""; 222*66f5808bSforsyth while ((c := stdin.getc()) >= 0 && c != '\n'){ 223*66f5808bSforsyth case c { 224*66f5808bSforsyth '\b' => 225*66f5808bSforsyth if (len s > 0) 226*66f5808bSforsyth s = s[0:len s - 1]; 227*66f5808bSforsyth 8r25 => # ^U 228*66f5808bSforsyth s = nil; 229*66f5808bSforsyth * => 230*66f5808bSforsyth s[len s] = c; 231*66f5808bSforsyth } 232*66f5808bSforsyth } 233*66f5808bSforsyth sys->fprint(stderr, "\n"); 234*66f5808bSforsyth return s; 235*66f5808bSforsyth} 236*66f5808bSforsyth 23737da2899SCharles.Forsythstream(src, dst: ref Sys->FD, bufsize: int) 23837da2899SCharles.Forsyth{ 23937da2899SCharles.Forsyth sys->stream(src, dst, bufsize); 24037da2899SCharles.Forsyth} 24137da2899SCharles.Forsyth 24237da2899SCharles.Forsythreadfile(f: string): array of byte 24337da2899SCharles.Forsyth{ 24437da2899SCharles.Forsyth fd := sys->open(f, Sys->OREAD); 24537da2899SCharles.Forsyth if (fd == nil) 24637da2899SCharles.Forsyth error(sys->sprint("cannot read %s: %r", f)); 24737da2899SCharles.Forsyth buf := array[8192] of byte; # >8K key? get real! 24837da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 24937da2899SCharles.Forsyth if (n <= 0) 25037da2899SCharles.Forsyth return nil; 25137da2899SCharles.Forsyth return buf[0:n]; 25237da2899SCharles.Forsyth} 25337da2899SCharles.Forsyth 25437da2899SCharles.Forsytherror(s: string) 25537da2899SCharles.Forsyth{ 25637da2899SCharles.Forsyth sys->fprint(stderr, "crypt: %s\n", s); 25737da2899SCharles.Forsyth fail("error"); 25837da2899SCharles.Forsyth} 25937da2899SCharles.Forsyth 26037da2899SCharles.Forsythfail(e: string) 26137da2899SCharles.Forsyth{ 26237da2899SCharles.Forsyth raise "fail: "+e; 26337da2899SCharles.Forsyth} 264