xref: /inferno-os/appl/cmd/crypt.b (revision 66f5808b81b1df84bc57c4f7b9d487201bc162fb)
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