shithub: riscv

Download patch

ref: 02cfcfeab46f36aad95263ed40d19df7bd5eddef
parent: f785d4da07349c7bb250eb00a3f2bed3eb170828
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Aug 19 17:06:17 EDT 2015

libauthsrv: generalize ticket service, not hardcoding ticket format and DES encryption

this is in preparation for replacing DES ticket encryption with
something better. but first need to make the code stop making
assumptions.

the wire encoding of the Ticket might be variable length
with TICKETLEN just giving an upper bound. the details will be
handled by libauthsrv _asgetticket() and _asgetresp() funciotns.

the Authenticator and Passwordreq structures are encrypted
with the random ticket key. The encryption schmeme will depend
on the Ticket format used, so we pass the Ticket* structure
instead of the DES key.

introduce Authkey structure that will hold all the required
cryptographic keys instead of passing DES key.

--- a/sys/include/authsrv.h
+++ b/sys/include/authsrv.h
@@ -12,6 +12,8 @@
 typedef struct	OChapreply	OChapreply;
 typedef struct	OMSchapreply	OMSchapreply;
 
+typedef struct	Authkey		Authkey;
+
 enum
 {
 	ANAMELEN=	28,	/* name max size in previous proto */
@@ -110,22 +112,27 @@
 };
 #define OMSCHAPREPLYLEN	(ANAMELEN+24+24)
 
+struct	Authkey
+{
+	char	des[DESKEYLEN];
+};
+
 /*
  *  convert to/from wire format
  */
-extern	int	convT2M(Ticket*, char*, char*);
-extern	void	convM2T(char*, Ticket*, char*);
-extern	int	convA2M(Authenticator*, char*, char*);
-extern	void	convM2A(char*, Authenticator*, char*);
-extern	int	convTR2M(Ticketreq*, char*);
-extern	void	convM2TR(char*, Ticketreq*);
-extern	int	convPR2M(Passwordreq*, char*, char*);
-extern	void	convM2PR(char*, Passwordreq*, char*);
+extern	int	convT2M(Ticket*, char*, int, Authkey*);
+extern	int	convM2T(char*, int, Ticket*, Authkey*);
+extern	int	convA2M(Authenticator*, char*, int, Ticket*);
+extern	int	convM2A(char*, int, Authenticator*, Ticket*);
+extern	int	convTR2M(Ticketreq*, char*, int);
+extern	int	convM2TR(char*, int, Ticketreq*);
+extern	int	convPR2M(Passwordreq*, char*, int, Ticket*);
+extern	int	convM2PR(char*, int, Passwordreq*, Ticket*);
 
 /*
  *  convert ascii password to DES key
  */
-extern	int	passtokey(char*, char*);
+extern	int	passtokey(Authkey*, char*);
 
 /*
  *  Nvram interface
@@ -167,5 +174,7 @@
 /*
  *  exchange messages with auth server
  */
-extern	int	_asgetticket(int, char*, char*);
+extern	int	_asgetticket(int, Ticketreq*, char*, int);
+extern	int	_asrequest(int, Ticketreq*);
+extern	int	_asgetresp(int, Ticket*, Authenticator*, Authkey *);
 extern	int	_asrdresp(int, char*, int);
--- a/sys/man/2/authsrv
+++ b/sys/man/2/authsrv
@@ -1,6 +1,6 @@
 .TH AUTHSRV 2
 .SH NAME
-authdial, passtokey, nvcsum, readnvram, convT2M, convM2T, convTR2M, convM2TR, convA2M, convM2A, convPR2M, convM2PR, _asgetticket, _asrdresp \- routines for communicating with authentication servers
+authdial, passtokey, nvcsum, readnvram, convT2M, convM2T, convTR2M, convM2TR, convA2M, convM2A, convPR2M, convM2PR, _asgetticket, _asrequest, _asgetresp, _asrdresp \- routines for communicating with authentication servers
 .SH SYNOPSIS
 .nf
 .PP
@@ -15,7 +15,7 @@
 int	authdial(char *netroot, char *ad);
 .PP
 .B
-int	passtokey(char key[DESKEYLEN], char *password)
+int	passtokey(Authkey *key, char *password)
 .PP
 .B
 uchar	nvcsum(void *mem, int len)
@@ -24,34 +24,40 @@
 int	readnvram(Nvrsafe *nv, int flag);
 .PPP
 .B
-int	convT2M(Ticket *t, char *msg, char *key)
+int	convT2M(Ticket *t, char *msg, int len, Authkey *key)
 .PP
 .B
-void	convM2T(char *msg, Ticket *t, char *key)
+int	convM2T(char *msg, int len, Ticket *t, Authkey *key)
 .PP
 .B
-int	convA2M(Authenticator *a, char *msg, char *key)
+int	convA2M(Authenticator *a, char *msg, int len, Ticket *t)
 .PP
 .B
-void	convM2A(char *msg, Authenticator *a, char *key)
+int	convM2A(char *msg, int len, Authenticator *a, Ticket *t)
 .PP
 .B
-int	convTR2M(Ticketreq *tr, char *msg)
+int	convTR2M(Ticketreq *tr, char *msg, int len)
 .PP
 .B
-void	convM2TR(char *msg, Ticketreq *tr)
+int	convM2TR(char *msg, int len, Ticketreq *tr)
 .PP
 .B
-int	convPR2M(Passwordreq *pr, char *msg, char *key)
+int	convPR2M(Passwordreq *pr, char *msg, int len, Ticket *t)
 .PP
 .B
-void	convM2PR(char *msg, Passwordreq *pr, char *key)
+int	convM2PR(char *msg, int len, Passwordreq *pr, Ticket *t)
 .PP
 .B
-int	_asgetticket(int fd, char *trbuf, char *tbuf);
+int	_asgetticket(int fd, Ticketreq *tr, char *buf, int len)
 .PP
 .B
-int	_asrdresp(int fd, char *buf, int len);
+int	_asrequest(int fd, Ticketreq *tr)
+.PP
+.B
+int	_asgetresp(int fd, Ticket *t, Authenticator *a, Authkey *key)
+.PP
+.B
+int	_asrdresp(int fd, char *buf, int len)
 .SH DESCRIPTION
 .I Authdial
 dials an authentication server over the
@@ -99,7 +105,9 @@
 .I Passtokey
 converts
 .I password
-into a DES key and stores the result in
+into a set of cryptographic keys and stores them in the
+.I Authkey
+structure
 .IR key .
 It returns 0 if
 .I password
@@ -213,18 +221,34 @@
 .I Key
 is used for encrypting the message before transmission and decrypting
 after reception.
+.IR ConvA2M ,
+.IR convM2A ,
+.I convPR2M
+and
+.I convM2PR
+encrypt/decrypt the message with the random ticket key.
 .PP
 The routine
+.I _asgetticket
+sends a ticket request
+.I tr
+returning the two encrypted tickets in
+.IR buf .
+The routine
+.I _asrequest
+encodes the ticket request
+.I tr
+and sends it not waiting for a response.
+After sending a request,
 .I _asgetresp
+can be used to receive the response containing a ticket and an optional
+authenticator and decrypts the ticket and authenticator using
+.IR key .
+The routine
+.I _asrdresp
 receives either a character array or an error string.
 On error, it sets errstr and returns -1.  If successful,
 it returns the number of bytes received.
-.PP
-The routine
-.I _asgetticket
-sends a ticket request message and then uses
-.I _asgetresp
-to recieve an answer.
 .SH SOURCE
 .B /sys/src/libauthsrv
 .SH SEE ALSO
--- a/sys/src/cmd/auth/as.c
+++ b/sys/src/cmd/auth/as.c
@@ -8,6 +8,7 @@
 #include <bio.h>
 #include <libsec.h>
 #include <auth.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 int	debug;
--- a/sys/src/cmd/auth/authcmdlib.h
+++ b/sys/src/cmd/auth/authcmdlib.h
@@ -39,13 +39,14 @@
 void	checksum(char*, char*);
 void	error(char*, ...);
 void	fail(char*);
-char*	findkey(char*, char*, char*);
+int	findkey(char*, char*, Authkey*);
+char*	finddeskey(char*, char*, char*);
 char*	findsecret(char*, char*, char*);
-int	getauthkey(char*);
+int	getauthkey(Authkey*);
 long	getexpiration(char *db, char *u);
-void	getpass(char*, char*, int, int);
+void	getpass(Authkey*, char*, int, int);
 int	getsecret(int, char*);
-int	keyfmt(Fmt*);
+int	deskeyfmt(Fmt*);
 void	logfail(char*);
 int	netcheck(void*, long, char*);
 char*	netdecimal(char*);
@@ -58,7 +59,8 @@
 void	readln(char*, char*, int, int);
 long	readn(int, void*, long);
 char*	secureidcheck(char*, char*);
-char*	setkey(char*, char*, char*);
+int	setkey(char*, char*, Authkey*);
+char*	setdeskey(char*, char*, char*);
 char*	setsecret(char*, char*, char*);
 int	smartcheck(void*, long, char*);
 void	succeed(char*);
--- a/sys/src/cmd/auth/authsrv.c
+++ b/sys/src/cmd/auth/authsrv.c
@@ -30,7 +30,9 @@
 int	speaksfor(char*, char*);
 void	replyerror(char*, ...);
 void	getraddr(char*);
-void	mkkey(char*);
+void	mkkey(Authkey*);
+int	samekey(Authkey*, Authkey*);
+void	mkticket(Ticketreq*, Ticket*);
 void	randombytes(uchar*, int);
 void	nthash(uchar hash[MShashlen], char *passwd);
 void	lmhash(uchar hash[MShashlen], char *passwd);
@@ -37,15 +39,15 @@
 void	ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom);
 void	mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);
 void	desencrypt(uchar data[8], uchar key[7]);
-int	tickauthreply(Ticketreq*, char*);
+int	tickauthreply(Ticketreq*, Authkey*);
 void	safecpy(char*, char*, int);
 
-
 void
 main(int argc, char *argv[])
 {
 	char buf[TICKREQLEN];
 	Ticketreq tr;
+	int n;
 
 	ARGBEGIN{
 	case 'd':
@@ -64,11 +66,10 @@
 
 	srand(time(0)*getpid());
 	for(;;){
-		if(readn(0, buf, TICKREQLEN) <= 0)
+		n = readn(0, buf, sizeof(buf));
+		if(n <= 0 || convM2TR(buf, n, &tr) <= 0)
 			exits(0);
-
-		convM2TR(buf, &tr);
-		switch(buf[0]){
+		switch(tr.type){
 		case AuthTreq:
 			ticketrequest(&tr);
 			break;
@@ -97,7 +98,7 @@
 			vnc(&tr);
 			break;
 		default:
-			syslog(0, AUTHLOG, "unknown ticket request type: %d", buf[0]);
+			syslog(0, AUTHLOG, "unknown ticket request type: %d", tr.type);
 			exits(0);
 		}
 	}
@@ -107,45 +108,39 @@
 int
 ticketrequest(Ticketreq *tr)
 {
-	char akey[DESKEYLEN];
-	char hkey[DESKEYLEN];
-	Ticket t;
+	Authkey akey, hkey;
 	char tbuf[2*TICKETLEN+1];
+	Ticket t;
+	int n;
 
-	if(findkey(KEYDB, tr->authid, akey) == 0){
+	if(!findkey(KEYDB, tr->authid, &akey)){
 		/* make one up so caller doesn't know it was wrong */
-		mkkey(akey);
+		mkkey(&akey);
 		if(debug)
 			syslog(0, AUTHLOG, "tr-fail authid %s", raddr);
 	}
-	if(findkey(KEYDB, tr->hostid, hkey) == 0){
+	if(!findkey(KEYDB, tr->hostid, &hkey)){
 		/* make one up so caller doesn't know it was wrong */
-		mkkey(hkey);
+		mkkey(&hkey);
 		if(debug)
 			syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr);
 	}
 
-	memset(&t, 0, sizeof(t));
-	memmove(t.chal, tr->chal, CHALLEN);
-	strcpy(t.cuid, tr->uid);
-	if(speaksfor(tr->hostid, tr->uid))
-		strcpy(t.suid, tr->uid);
-	else {
-		mkkey(akey);
-		mkkey(hkey);
+	mkticket(tr, &t);
+	if(!speaksfor(tr->hostid, tr->uid)){
+		mkkey(&akey);
+		mkkey(&hkey);
 		if(debug)
 			syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",
 				tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
 	}
-
-	mkkey(t.key);
-
-	tbuf[0] = AuthOK;
+	n = 0;
+	tbuf[n++] = AuthOK;
 	t.num = AuthTc;
-	convT2M(&t, tbuf+1, hkey);
+	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &hkey);
 	t.num = AuthTs;
-	convT2M(&t, tbuf+1+TICKETLEN, akey);
-	if(write(1, tbuf, 2*TICKETLEN+1) < 0){
+	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &akey);
+	if(write(1, tbuf, n) < 0){
 		if(debug)
 			syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup",
 				tr->uid, tr->hostid, raddr);
@@ -163,22 +158,23 @@
 {
 	long chal;
 	char *key, *netkey;
-	char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], hkey[DESKEYLEN];
+	Authkey hkey;
+	char kbuf[DESKEYLEN], nkbuf[DESKEYLEN];
 	char buf[NETCHLEN+1];
 	char *err;
 
-	key = findkey(KEYDB, tr->uid, kbuf);
-	netkey = findkey(NETKEYDB, tr->uid, nkbuf);
-	if(key == 0 && netkey == 0){
+	key = finddeskey(KEYDB, tr->uid, kbuf);
+	netkey = finddeskey(NETKEYDB, tr->uid, nkbuf);
+	if(key == nil && netkey == nil){
 		/* make one up so caller doesn't know it was wrong */
-		mkkey(nkbuf);
+		randombytes((uchar*)nkbuf, DESKEYLEN);
 		netkey = nkbuf;
 		if(debug)
 			syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr);
 	}
-	if(findkey(KEYDB, tr->hostid, hkey) == 0){
+	if(!findkey(KEYDB, tr->hostid, &hkey)){
 		/* make one up so caller doesn't know it was wrong */
-		mkkey(hkey);
+		mkkey(&hkey);
 		if(debug)
 			syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid,
 				tr->uid, raddr);
@@ -195,8 +191,8 @@
 		exits(0);
 	if(readn(0, buf, NETCHLEN) < 0)
 		exits(0);
-	if(!(key && netcheck(key, chal, buf))
-	&& !(netkey && netcheck(netkey, chal, buf))
+	if(!(key != nil && netcheck(key, chal, buf))
+	&& !(netkey != nil && netcheck(netkey, chal, buf))
 	&& (err = secureidcheck(tr->uid, buf)) != nil){
 		replyerror("cr-fail %s %s %s", err, tr->uid, raddr);
 		logfail(tr->uid);
@@ -210,7 +206,7 @@
 	/*
 	 *  reply with ticket & authenticator
 	 */
-	if(tickauthreply(tr, hkey) < 0){
+	if(tickauthreply(tr, &hkey) < 0){
 		if(debug)
 			syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup",
 				tr->uid, tr->hostid, raddr);
@@ -229,36 +225,36 @@
 	char tbuf[TICKETLEN+1];
 	char prbuf[PASSREQLEN];
 	Passwordreq pr;
-	char okey[DESKEYLEN], nkey[DESKEYLEN];
+	Authkey okey, nkey;
 	char *err;
+	int n;
 
-	if(findkey(KEYDB, tr->uid, okey) == 0){
+	if(!findkey(KEYDB, tr->uid, &okey)){
 		/* make one up so caller doesn't know it was wrong */
-		mkkey(okey);
+		mkkey(&okey);
 		syslog(0, AUTHLOG, "cp-fail uid %s", raddr);
 	}
 
 	/* send back a ticket with a new key */
-	memmove(t.chal, tr->chal, CHALLEN);
-	mkkey(t.key);
-	tbuf[0] = AuthOK;
+	mkticket(tr, &t);
 	t.num = AuthTp;
-	safecpy(t.cuid, tr->uid, sizeof(t.cuid));
-	safecpy(t.suid, tr->uid, sizeof(t.suid));
-	convT2M(&t, tbuf+1, okey);
-	write(1, tbuf, sizeof(tbuf));
+	n = 0;
+	tbuf[n++] = AuthOK;
+	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &okey);
+	if(write(1, tbuf, n) != n)
+		exits(0);
 
 	/* loop trying passwords out */
 	for(;;){
-		if(readn(0, prbuf, PASSREQLEN) < 0)
+		n = readn(0, prbuf, sizeof(prbuf));
+		if(n <= 0 || convM2PR(prbuf, n, &pr, &t) <= 0)
 			exits(0);
-		convM2PR(prbuf, &pr, t.key);
 		if(pr.num != AuthPass){
 			replyerror("protocol botch1: %s", raddr);
 			exits(0);
 		}
-		passtokey(nkey, pr.old);
-		if(memcmp(nkey, okey, DESKEYLEN)){
+		passtokey(&nkey, pr.old);
+		if(!samekey(&nkey, &okey)){
 			replyerror("protocol botch2: %s", raddr);
 			continue;
 		}
@@ -268,13 +264,13 @@
 				replyerror("%s %s", err, raddr);
 				continue;
 			}
-			passtokey(nkey, pr.new);
+			passtokey(&nkey, pr.new);
 		}
 		if(pr.changesecret && setsecret(KEYDB, tr->uid, pr.secret) == 0){
 			replyerror("can't write secret %s", raddr);
 			continue;
 		}
-		if(*pr.new && setkey(KEYDB, tr->uid, nkey) == 0){
+		if(*pr.new && setkey(KEYDB, tr->uid, &nkey) == 0){
 			replyerror("can't write key %s", raddr);
 			continue;
 		}
@@ -292,15 +288,14 @@
 {
 	Ticket t;
 	char tbuf[TICKETLEN+1];
-	char key[DESKEYLEN];
+	Authkey key;
 	char *p;
 	Biobuf *b;
 	int n;
 
-	randombytes((uchar*)key, DESKEYLEN);
-
 	/* use plan9 key when there is any */
-	findkey(KEYDB, tr->uid, key);
+	if(!findkey(KEYDB, tr->uid, &key))
+		mkkey(&key);
 
 	n = strlen(tr->uid);
 	b = Bopen("/sys/lib/httppasswords", OREAD);
@@ -315,7 +310,7 @@
 				p += n;
 				while(*p == ' ' || *p == '\t')
 					p++;
-				passtokey(key, p);
+				passtokey(&key, p);
 			}
 		}
 		Bterm(b);
@@ -322,14 +317,13 @@
 	}
 
 	/* send back a ticket encrypted with the key */
+	mkticket(tr, &t);
 	randombytes((uchar*)t.chal, CHALLEN);
-	mkkey(t.key);
-	tbuf[0] = AuthOK;
 	t.num = AuthHr;
-	safecpy(t.cuid, tr->uid, sizeof(t.cuid));
-	safecpy(t.suid, tr->uid, sizeof(t.suid));
-	convT2M(&t, tbuf+1, key);
-	write(1, tbuf, sizeof(tbuf));
+	n = 0;
+	tbuf[n++] = AuthOK;
+	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &key);
+	write(1, tbuf, n);
 }
 
 static char*
@@ -339,13 +333,13 @@
 	static char *domain;
 	int n;
 
-	if(domain)
+	if(domain != nil)
 		return domain;
 	if(*sysname)
 		return sysname;
 
 	domain = csgetvalue(0, "sys", sysname, "dom", nil);
-	if(domain)
+	if(domain != nil)
 		return domain;
 
 	n = readfile("/dev/sysname", sysname, sizeof(sysname)-1);
@@ -373,12 +367,13 @@
 void
 apop(Ticketreq *tr, int type)
 {
-	int challen, i, tries;
-	char *secret, *hkey, *p;
+	int challen, i, n, tries;
+	char *secret, *p;
+	Authkey hkey;
 	Ticketreq treq;
 	DigestState *s;
-	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
-	char tbuf[TICKREQLEN];
+	char sbuf[SECRETLEN];
+	char trbuf[TICKREQLEN];
 	char buf[MD5dlen*2];
 	uchar digest[MD5dlen], resp[MD5dlen];
 	ulong rb[4];
@@ -401,9 +396,9 @@
 		/*
 		 *  get ticket request
 		 */
-		if(readn(0, tbuf, TICKREQLEN) < 0)
+		n = readn(0, trbuf, sizeof(trbuf));
+		if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0)
 			exits(0);
-		convM2TR(tbuf, &treq);
 		tr = &treq;
 		if(tr->type != type)
 			exits(0);
@@ -411,7 +406,7 @@
 		/*
 		 * read response
 		 */
-		if(readn(0, buf, MD5dlen*2) < 0)
+		if(readn(0, buf, MD5dlen*2) != MD5dlen*2)
 			exits(0);
 		for(i = 0; i < MD5dlen; i++)
 			resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]);
@@ -420,8 +415,7 @@
 		 * lookup
 		 */
 		secret = findsecret(KEYDB, tr->uid, sbuf);
-		hkey = findkey(KEYDB, tr->hostid, hbuf);
-		if(hkey == 0 || secret == 0){
+		if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){
 			replyerror("apop-fail bad response %s", raddr);
 			logfail(tr->uid);
 			if(tries > 5)
@@ -455,7 +449,7 @@
 	/*
 	 *  reply with ticket & authenticator
 	 */
-	if(tickauthreply(tr, hkey) < 0)
+	if(tickauthreply(tr, &hkey) < 0)
 		exits(0);
 
 	if(debug){
@@ -493,10 +487,11 @@
 void
 vnc(Ticketreq *tr)
 {
+	char *secret;
+	Authkey hkey;
 	uchar chal[VNCchallen+6];
 	uchar reply[VNCchallen];
-	char *secret, *hkey;
-	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
+	char sbuf[SECRETLEN];
 	DESstate s;
 	int i;
 
@@ -514,7 +509,7 @@
 	 */
 	memset(sbuf, 0, sizeof(sbuf));
 	secret = findsecret(KEYDB, tr->uid, sbuf);
-	if(secret == 0){
+	if(secret == nil){
 		randombytes((uchar*)sbuf, sizeof(sbuf));
 		secret = sbuf;
 	}
@@ -521,11 +516,8 @@
 	for(i = 0; i < 8; i++)
 		secret[i] = swizzletab[(uchar)secret[i]];
 
-	hkey = findkey(KEYDB, tr->hostid, hbuf);
-	if(hkey == 0){
-		randombytes((uchar*)hbuf, sizeof(hbuf));
-		hkey = hbuf;
-	}
+	if(!findkey(KEYDB, tr->hostid, &hkey))
+		mkkey(&hkey);
 
 	/*
 	 *  get response
@@ -548,7 +540,7 @@
 	/*
 	 *  reply with ticket & authenticator
 	 */
-	if(tickauthreply(tr, hkey) < 0)
+	if(tickauthreply(tr, &hkey) < 0)
 		exits(0);
 
 	if(debug)
@@ -558,9 +550,10 @@
 void
 chap(Ticketreq *tr)
 {
-	char *secret, *hkey;
+	char *secret;
+	Authkey hkey;
 	DigestState *s;
-	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
+	char sbuf[SECRETLEN];
 	uchar digest[MD5dlen];
 	char chal[CHALLEN];
 	OChapreply reply;
@@ -582,8 +575,7 @@
 	 * lookup
 	 */
 	secret = findsecret(KEYDB, tr->uid, sbuf);
-	hkey = findkey(KEYDB, tr->hostid, hbuf);
-	if(hkey == 0 || secret == 0){
+	if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){
 		replyerror("chap-fail bad response %s", raddr);
 		logfail(tr->uid);
 		exits(0);
@@ -607,7 +599,7 @@
 	/*
 	 *  reply with ticket & authenticator
 	 */
-	if(tickauthreply(tr, hkey) < 0)
+	if(tickauthreply(tr, &hkey) < 0)
 		exits(0);
 
 	if(debug)
@@ -671,8 +663,9 @@
 void
 mschap(Ticketreq *tr)
 {
-	char *secret, *hkey;
-	char sbuf[SECRETLEN], hbuf[DESKEYLEN], windom[128];
+	char *secret;
+	Authkey hkey;
+	char sbuf[SECRETLEN], windom[128];
 	uchar chal[CHALLEN], ntblob[1024];
 	uchar hash[MShashlen];
 	uchar hash2[MShashlen];
@@ -743,8 +736,7 @@
 	 * lookup
 	 */
 	secret = findsecret(KEYDB, tr->uid, sbuf);
-	hkey = findkey(KEYDB, tr->hostid, hbuf);
-	if(hkey == 0 || secret == 0){
+	if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){
 		replyerror("mschap-fail bad response %s/%s(%s)",
 			tr->uid, tr->hostid, raddr);
 		logfail(tr->uid);
@@ -812,7 +804,7 @@
 	/*
 	 *  reply with ticket & authenticator
 	 */
-	if(tickauthreply(tr, hkey) < 0)
+	if(tickauthreply(tr, &hkey) < 0)
 		exits(0);
 
 	if(debug)
@@ -939,16 +931,16 @@
 	if(strcmp(speaker, user) == 0)
 		return 1;
 
-	if(db == 0)
+	if(db == nil)
 		return 0;
 
 	tp = ndbsearch(db, &s, "hostid", speaker);
-	if(tp == 0)
+	if(tp == nil)
 		return 0;
 
 	ok = 0;
 	snprint(notuser, sizeof notuser, "!%s", user);
-	for(ntp = tp; ntp; ntp = ntp->entry)
+	for(ntp = tp; ntp != nil; ntp = ntp->entry)
 		if(strcmp(ntp->attr, "uid") == 0){
 			if(strcmp(ntp->val, notuser) == 0){
 				ok = 0;
@@ -1003,12 +995,28 @@
 }
 
 void
-mkkey(char *k)
+mkkey(Authkey *k)
 {
-	randombytes((uchar*)k, DESKEYLEN);
+	randombytes((uchar*)k->des, DESKEYLEN);
 }
 
+int
+samekey(Authkey *a, Authkey *b)
+{
+	return memcmp(a->des, b->des, DESKEYLEN) == 0;
+}
+
 void
+mkticket(Ticketreq *tr, Ticket *t)
+{
+	memset(t, 0, sizeof(Ticket));
+	memmove(t->chal, tr->chal, CHALLEN);
+	safecpy(t->cuid, tr->uid, sizeof(t->cuid));
+	safecpy(t->suid, tr->uid, sizeof(t->suid));
+	randombytes((uchar*)t->key, DESKEYLEN);
+}
+
+void
 randombytes(uchar *buf, int len)
 {
 	int i;
@@ -1024,25 +1032,24 @@
  *  reply with ticket and authenticator
  */
 int
-tickauthreply(Ticketreq *tr, char *hkey)
+tickauthreply(Ticketreq *tr, Authkey *hkey)
 {
 	Ticket t;
 	Authenticator a;
 	char buf[TICKETLEN+AUTHENTLEN+1];
+	int n;
 
-	memset(&t, 0, sizeof(t));
-	memmove(t.chal, tr->chal, CHALLEN);
-	safecpy(t.cuid, tr->uid, sizeof t.cuid);
-	safecpy(t.suid, tr->uid, sizeof t.suid);
-	mkkey(t.key);
-	buf[0] = AuthOK;
+	mkticket(tr, &t);
 	t.num = AuthTs;
-	convT2M(&t, buf+1, hkey);
+	n = 0;
+	buf[n++] = AuthOK;
+	n += convT2M(&t, buf+n, sizeof(buf)-n, hkey);
+	memset(&a, 0, sizeof(a));
 	memmove(a.chal, t.chal, CHALLEN);
 	a.num = AuthAc;
 	a.id = 0;
-	convA2M(&a, buf+TICKETLEN+1, t.key);
-	if(write(1, buf, TICKETLEN+AUTHENTLEN+1) < 0)
+	n += convA2M(&a, buf+n, sizeof(buf)-n, &t);
+	if(write(1, buf, n) != n)
 		return -1;
 	return 0;
 }
@@ -1053,3 +1060,4 @@
 	strncpy(to, from, len);
 	to[len-1] = 0;
 }
+
--- a/sys/src/cmd/auth/changeuser.c
+++ b/sys/src/cmd/auth/changeuser.c
@@ -5,7 +5,7 @@
 #include <bio.h>
 #include "authcmdlib.h"
 
-void	install(char*, char*, char*, long, int);
+void	install(char*, char*, Authkey*, long, int);
 int	exists (char*, char*);
 
 void
@@ -18,14 +18,15 @@
 void
 main(int argc, char *argv[])
 {
-	char *u, key[DESKEYLEN], answer[32], p9pass[32];
+	char *u, answer[32], p9pass[32];
 	int which, i, newkey, newbio, dosecret;
 	long t;
+	Authkey key;
 	Acctbio a;
 	Fs *f;
 
 	srand(getpid()*time(0));
-	fmtinstall('K', keyfmt);
+	fmtinstall('K', deskeyfmt);
 
 	which = 0;
 	ARGBEGIN{
@@ -61,10 +62,10 @@
 				newkey = 0;
 		}
 		if(newkey)
-			getpass(key, p9pass, 1, 1);
+			getpass(&key, p9pass, 1, 1);
 		dosecret = getsecret(newkey, p9pass);
 		t = getexpiration(f->keys, u);
-		install(f->keys, u, key, t, newkey);
+		install(f->keys, u, &key, t, newkey);
 		if(dosecret && setsecret(KEYDB, u, p9pass) == 0)
 			error("error writing Inferno/pop secret");
 		newbio = querybio(f->who, u, &a);
@@ -83,17 +84,17 @@
 		}
 		if(newkey)
 			for(i=0; i<DESKEYLEN; i++)
-				key[i] = nrand(256);
+				key.des[i] = nrand(256);
 		if(a.user == 0){
 			t = getexpiration(f->keys, u);
 			newbio = querybio(f->who, u, &a);
 		}
-		install(f->keys, u, key, t, newkey);
+		install(f->keys, u, &key, t, newkey);
 		if(newbio)
 			wrbio(f->who, &a);
-		findkey(f->keys, u, key);
-		print("user %s: SecureNet key: %K\n", u, key);
-		checksum(key, answer);
+		finddeskey(f->keys, u, key.des);
+		print("user %s: SecureNet key: %K\n", u, key.des);
+		checksum(key.des, answer);
 		print("verify with checksum %s\n", answer);
 		print("user %s installed for SecureNet\n", u);
 		syslog(0, AUTHLOG, "user %s installed for securenet", u);
@@ -102,7 +103,7 @@
 }
 
 void
-install(char *db, char *u, char *key, long t, int newkey)
+install(char *db, char *u, Authkey *key, long t, int newkey)
 {
 	char buf[KEYDBBUF+ANAMELEN+20];
 	int fd;
@@ -118,7 +119,7 @@
 	if(newkey){
 		sprint(buf, "%s/%s/key", db, u);
 		fd = open(buf, OWRITE);
-		if(fd < 0 || write(fd, key, DESKEYLEN) != DESKEYLEN)
+		if(fd < 0 || write(fd, key->des, DESKEYLEN) != DESKEYLEN)
 			error("can't set key: %r");
 		close(fd);
 	}
--- a/sys/src/cmd/auth/convkeys.c
+++ b/sys/src/cmd/auth/convkeys.c
@@ -7,12 +7,11 @@
 #include <bio.h>
 #include "authcmdlib.h"
 
-char	authkey[DESKEYLEN];
+Authkey	authkey;
 int	verb;
 int	usepass;
 
-int	convert(char*, char*, int);
-int	dofcrypt(int, char*, char*, int);
+int	convert(char*, Authkey*, int);
 void	usage(void);
 
 void
@@ -19,7 +18,8 @@
 main(int argc, char *argv[])
 {
 	Dir *d;
-	char *p, *file, key[DESKEYLEN];
+	Authkey key;
+	char *p, *file;
 	int fd, len;
 
 	ARGBEGIN{
@@ -40,12 +40,12 @@
 	/* get original key */
 	if(usepass){
 		print("enter password file is encoded with\n");
-		getpass(authkey, nil, 0, 1);
+		getpass(&authkey, nil, 0, 1);
 	} else
-		getauthkey(authkey);
+		getauthkey(&authkey);
 	if(!verb){
 		print("enter password to reencode with\n");
-		getpass(key, nil, 0, 1);
+		getpass(&key, nil, 0, 1);
 	}
 
 	fd = open(file, ORDWR);
@@ -60,7 +60,7 @@
 		error("out of memory");
 	if(read(fd, p, len) != len)
 		error("can't read key file: %r\n");
-	len = convert(p, key, len);
+	len = convert(p, &key, len);
 	if(verb)
 		exits(0);
 	if(pwrite(fd, p, len, 0) != len)
@@ -128,7 +128,7 @@
 }
 
 int
-convert(char *p, char *key, int len)
+convert(char *p, Authkey *key, int len)
 {
 	int i;
 
@@ -139,7 +139,7 @@
 		len -= len % KEYDBLEN;
 	}
 	len += KEYDBOFF;
-	oldCBCdecrypt(authkey, p, len);
+	oldCBCdecrypt(authkey.des, p, len);
 	for(i = KEYDBOFF; i < len; i += KEYDBLEN)
 		if (badname(&p[i])) {
 			print("bad name %.30s... - aborting\n", &p[i]);
@@ -150,7 +150,7 @@
 			print("%s\n", &p[i]);
 
 	randombytes((uchar*)p, 8);
-	oldCBCencrypt(key, p, len);
+	oldCBCencrypt(key->des, p, len);
 	return len;
 }
 
--- a/sys/src/cmd/auth/convkeys2.c
+++ b/sys/src/cmd/auth/convkeys2.c
@@ -6,12 +6,11 @@
 #include <bio.h>
 #include "authcmdlib.h"
 
-char	authkey[DESKEYLEN];
+Authkey	authkey;
 int	verb;
 int	usepass;
 
-int	convert(char*, char*, char*, int);
-int	dofcrypt(int, char*, char*, int);
+int	convert(char*, char*, Authkey*, int);
 void	usage(void);
 void	randombytes(uchar*, int);
 
@@ -19,7 +18,8 @@
 main(int argc, char *argv[])
 {
 	Dir *d;
-	char *p, *np, *file, key[DESKEYLEN];
+	Authkey key;
+	char *p, *np, *file;
 	int fd, len;
 
 	ARGBEGIN{
@@ -40,11 +40,11 @@
 	/* get original key */
 	if(usepass){
 		print("enter password file is encoded with\n");
-		getpass(authkey, nil, 0, 1);
+		getpass(&authkey, nil, 0, 1);
 	} else
-		getauthkey(authkey);
+		getauthkey(&authkey);
 	print("enter password to reencode with\n");
-	getpass(key, nil, 0, 1);
+	getpass(&key, nil, 0, 1);
 
 	fd = open(file, ORDWR);
 	if(fd < 0)
@@ -61,7 +61,7 @@
 		error("out of memory");
 	if(read(fd, p, len) != len)
 		error("can't read key file: %r\n");
-	len = convert(p, np, key, len);
+	len = convert(p, np, &key, len);
 	if(verb)
 		exits(0);
 	if(pwrite(fd, np, len, 0) != len)
@@ -84,7 +84,7 @@
 }
 
 int
-convert(char *p, char *np, char *key, int len)
+convert(char *p, char *np, Authkey *key, int len)
 {
 	int i, off, noff;
 
@@ -95,7 +95,7 @@
 	for(i = 0; i < len; i ++){
 		off = i*OKEYDBLEN;
 		noff = KEYDBOFF+i*(KEYDBLEN);
-		decrypt(authkey, &p[off], OKEYDBLEN);
+		decrypt(authkey.des, &p[off], OKEYDBLEN);
 		memmove(&np[noff], &p[off], OKEYDBLEN);
 		memset(&np[noff-SECRETLEN], 0, SECRETLEN);
 		if(verb)
@@ -103,7 +103,7 @@
 	}
 	randombytes((uchar*)np, KEYDBOFF);
 	len = (len*KEYDBLEN) + KEYDBOFF;
-	oldCBCencrypt(key, np, len);
+	oldCBCencrypt(key->des, np, len);
 	return len;
 }
 
--- a/sys/src/cmd/auth/cron.c
+++ b/sys/src/cmd/auth/cron.c
@@ -3,6 +3,7 @@
 #include <bio.h>
 #include <libsec.h>
 #include <auth.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 char CRONLOG[] = "cron";
--- a/sys/src/cmd/auth/debug.c
+++ b/sys/src/cmd/auth/debug.c
@@ -208,9 +208,9 @@
 void
 authfutz(char *dom, char *user)
 {
-	int fd, nobootes;
-	char pw[128], prompt[128], key[DESKEYLEN], booteskey[DESKEYLEN], tbuf[2*TICKETLEN],
-		trbuf[TICKREQLEN];
+	int fd, nobootes, n, m;
+	char pw[128], prompt[128], tbuf[2*TICKETLEN];
+	Authkey key, booteskey;
 	Ticket t;
 	Ticketreq tr;
 
@@ -218,7 +218,7 @@
 	readcons(prompt, nil, 1, pw, sizeof pw);
 	if(pw[0] == '\0')
 		return;
-	passtokey(key, pw);
+	passtokey(&key, pw);
 
 	fd = authdial(nil, dom);
 	if(fd < 0){
@@ -227,6 +227,7 @@
 	}
 
 	/* try ticket request using just user key */
+	memset(&tr, 0, sizeof(tr));
 	tr.type = AuthTreq;
 	strecpy(tr.authid, tr.authid+sizeof tr.authid, user);
 	strecpy(tr.authdom, tr.authdom+sizeof tr.authdom, dom);
@@ -233,13 +234,12 @@
 	strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
 	strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
 	memset(tr.chal, 0xAA, sizeof tr.chal);
-	convTR2M(&tr, trbuf);
-	if(_asgetticket(fd, trbuf, tbuf) < 0){
-		close(fd);
+	if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){
 		print("\t_asgetticket failed: %r\n");
+		close(fd);
 		return;
 	}
-	convM2T(tbuf, &t, key);
+	m = convM2T(tbuf, n, &t, &key);
 	if(t.num != AuthTc){
 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
@@ -252,7 +252,7 @@
 		return;
 	}
 
-	convM2T(tbuf+TICKETLEN, &t, key);
+	convM2T(tbuf+m, n-m, &t, &key);
 	if(t.num != AuthTs){
 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
@@ -269,13 +269,12 @@
 	/* try ticket request using bootes key */
 	snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
 	readcons(prompt, "glenda", 0, tr.authid, sizeof tr.authid);
-	convTR2M(&tr, trbuf);
-	if(_asgetticket(fd, trbuf, tbuf) < 0){
+	if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){
 		close(fd);
 		print("\t_asgetticket failed: %r\n");
 		return;
 	}
-	convM2T(tbuf, &t, key);
+	m = convM2T(tbuf, n, &t, &key);
 	if(t.num != AuthTc){
 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
@@ -295,9 +294,9 @@
 		goto Nobootes;
 	}
 	nobootes = 0;
-	passtokey(booteskey, pw);
+	passtokey(&booteskey, pw);
 
-	convM2T(tbuf+TICKETLEN, &t, booteskey);
+	convM2T(tbuf+m, n-m, &t, &booteskey);
 	if(t.num != AuthTs){
 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
 		print("\tauth server and you do not agree on key for %s@%s\n", tr.authid, dom);
--- a/sys/src/cmd/auth/factotum/apop.c
+++ b/sys/src/cmd/auth/factotum/apop.c
@@ -208,7 +208,7 @@
 static int
 dochal(State *s)
 {
-	char *dom, *user, trbuf[TICKREQLEN];
+	char *dom, *user;
 	int n;
 
 	s->asfd = -1;
@@ -228,13 +228,11 @@
 		goto err;
 
 	memset(&s->tr, 0, sizeof(s->tr));
-	s->tr.type = s->astype;
 	safecpy(s->tr.authdom, dom, sizeof s->tr.authdom);
 	safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
-	convTR2M(&s->tr, trbuf);
-
+	s->tr.type = s->astype;
 	alarm(30*1000);
-	if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN){
+	if(_asrequest(s->asfd, &s->tr) < 0){
 		alarm(0);
 		goto err;
 	}
@@ -254,8 +252,6 @@
 static int
 doreply(State *s, char *user, char *response)
 {
-	char ticket[TICKETLEN+AUTHENTLEN];
-	char trbuf[TICKREQLEN];
 	int n;
 	Authenticator a;
 
@@ -267,21 +263,16 @@
 
 	memrandom(s->tr.chal, CHALLEN);
 	safecpy(s->tr.uid, user, sizeof(s->tr.uid));
-	convTR2M(&s->tr, trbuf);
 	alarm(30*1000);
-	if((n=write(s->asfd, trbuf, TICKREQLEN)) != TICKREQLEN){
+	if(_asrequest(s->asfd, &s->tr) < 0){
 		alarm(0);
-		if(n >= 0)
-			werrstr("short write to auth server");
 		goto err;
 	}
-	if((n=write(s->asfd, response, MD5dlen*2)) != MD5dlen*2){
+	if(write(s->asfd, response, MD5dlen*2) != MD5dlen*2){
 		alarm(0);
-		if(n >= 0)
-			werrstr("short write to auth server");
 		goto err;
 	}
-	n = _asrdresp(s->asfd, ticket, TICKETLEN+AUTHENTLEN);
+	n = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv);
 	alarm(0);
 	if(n < 0){
 		/* leave connection open so we can try again */
@@ -290,7 +281,6 @@
 	close(s->asfd);
 	s->asfd = -1;
 
-	convM2T(ticket, &s->t, (char*)s->key->priv);
 	if(s->t.num != AuthTs
 	|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
 		if(s->key->successes == 0)
@@ -299,7 +289,6 @@
 		goto err;
 	}
 	s->key->successes++;
-	convM2A(ticket+TICKETLEN, &a, s->t.key);
 	if(a.num != AuthAc
 	|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
 	|| a.id != 0){
@@ -306,7 +295,6 @@
 		werrstr(Easproto);
 		goto err;
 	}
-
 	return 0;
 err:
 	if(s->asfd >= 0)
--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -299,8 +299,7 @@
 dochal(State *s)
 {
 	char *dom, *user;
-	char trbuf[TICKREQLEN];
-	int ret;
+	int n;
 
 	s->asfd = -1;
 
@@ -315,20 +314,17 @@
 		goto err;
 	
 	memset(&s->tr, 0, sizeof(s->tr));
-	s->tr.type = s->astype;
 	safecpy(s->tr.authdom, dom, sizeof(s->tr.authdom));
 	safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
-	convTR2M(&s->tr, trbuf);
-
+	s->tr.type = s->astype;
 	alarm(30*1000);
-	if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN){
+	if(_asrequest(s->asfd, &s->tr) < 0){
 		alarm(0);
 		goto err;
 	}
-	/* readn, not _asrdresp.  needs to match auth.srv.c. */
-	ret = readn(s->asfd, s->chal, sizeof s->chal);
+	n = readn(s->asfd, s->chal, sizeof s->chal);
 	alarm(0);
-	if(ret != sizeof s->chal)
+	if(n != sizeof s->chal)
 		goto err;
 
 	return 0;
@@ -343,18 +339,16 @@
 static int
 doreply(State *s, uchar *reply, int nreply)
 {
-	char ticket[TICKETLEN+AUTHENTLEN];
 	int n;
 	Authenticator a;
 
 	alarm(30*1000);
-	if((n=write(s->asfd, reply, nreply)) != nreply){
+	if(write(s->asfd, reply, nreply) != nreply){
 		alarm(0);
-		if(n >= 0)
-			werrstr("short write to auth server");
 		goto err;
 	}
-	if(_asrdresp(s->asfd, ticket, TICKETLEN+AUTHENTLEN) < 0){
+	n = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv);
+	if(n < 0){
 		alarm(0);
 		/* leave connection open so we can try again */
 		return -1;
@@ -365,7 +359,7 @@
 		s->nsecret = 0;
 	close(s->asfd);
 	s->asfd = -1;
-	convM2T(ticket, &s->t, s->key->priv);
+
 	if(s->t.num != AuthTs
 	|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
 		if(s->key->successes == 0)
@@ -374,7 +368,6 @@
 		return -1;
 	}
 	s->key->successes++;
-	convM2A(ticket+TICKETLEN, &a, s->t.key);
 	if(a.num != AuthAc
 	|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
 	|| a.id != 0){
@@ -381,7 +374,6 @@
 		werrstr(Easproto);
 		return -1;
 	}
-
 	return 0;
 err:
 	if(s->asfd >= 0)
--- a/sys/src/cmd/auth/factotum/p9cr.c
+++ b/sys/src/cmd/auth/factotum/p9cr.c
@@ -165,7 +165,7 @@
 static int
 p9response(Fsstate *fss, State *s)
 {
-	char key[DESKEYLEN];
+	Authkey key;
 	uchar buf[8];
 	ulong chal;
 	char *pw;
@@ -173,10 +173,10 @@
 	pw = _strfindattr(s->key->privattr, "!password");
 	if(pw == nil)
 		return failure(fss, "vncresponse cannot happen");
-	passtokey(key, pw);
+	passtokey(&key, pw);
 	memset(buf, 0, 8);
 	sprint((char*)buf, "%d", atoi(s->chal));
-	if(encrypt(key, buf, 8) < 0)
+	if(encrypt(key.des, buf, 8) < 0)
 		return failure(fss, "can't encrypt response");
 	chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
 	s->resplen = snprint(s->resp, sizeof s->resp, "%.8lux", chal);
@@ -247,7 +247,6 @@
 static int
 p9crwrite(Fsstate *fss, void *va, uint n)
 {
-	char tbuf[TICKETLEN+AUTHENTLEN];
 	State *s;
 	char *data = va;
 	Authenticator a;
@@ -288,7 +287,7 @@
 			return failure(fss, Easproto);
 		}
 		/* get ticket plus authenticator from auth server */
-		ret = _asrdresp(s->asfd, tbuf, TICKETLEN+AUTHENTLEN);
+		ret = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv);
 		alarm(0);
 
 		if(ret < 0)
@@ -295,7 +294,6 @@
 			return failure(fss, nil);
 
 		/* check ticket */
-		convM2T(tbuf, &s->t, s->key->priv);
 		if(s->t.num != AuthTs
 		|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
 			if (s->key->successes == 0)
@@ -303,7 +301,6 @@
 			return failure(fss, Easproto);
 		}
 		s->key->successes++;
-		convM2A(tbuf+TICKETLEN, &a, s->t.key);
 		if(a.num != AuthAc
 		|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
 		|| a.id != 0)
@@ -322,13 +319,11 @@
 static int
 getchal(State *s, Fsstate *fss)
 {
-	char trbuf[TICKREQLEN];
 	int n;
 
 	safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof(s->tr.hostid));
 	safecpy(s->tr.authdom, _strfindattr(s->key->attr, "dom"), sizeof(s->tr.authdom));
 	s->tr.type = s->astype;
-	convTR2M(&s->tr, trbuf);
 
 	/* get challenge from auth server */
 	s->asfd = _authdial(nil, _strfindattr(s->key->attr, "dom"));
@@ -335,7 +330,7 @@
 	if(s->asfd < 0)
 		return failure(fss, Easproto);
 	alarm(30*1000);
-	if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN){
+	if(_asrequest(s->asfd, &s->tr) < 0){
 		alarm(0);
 		return failure(fss, Easproto);
 	}
--- a/sys/src/cmd/auth/factotum/p9sk1.c
+++ b/sys/src/cmd/auth/factotum/p9sk1.c
@@ -25,7 +25,7 @@
 	Ticketreq tr;
 	char cchal[CHALLEN];
 	char tbuf[TICKETLEN+AUTHENTLEN];
-	char authkey[DESKEYLEN];
+	int tbuflen;
 	uchar *secret;
 	int speakfor;
 };
@@ -60,7 +60,7 @@
 [SHaveAuth]		"SHaveAuth",
 };
 
-static int gettickets(State*, char*, char*);
+static int gettickets(State*, Ticketreq *, char*, int);
 
 static int
 p9skinit(Proto *p, Fsstate *fss)
@@ -119,6 +119,8 @@
 			break;
 		}
 	}
+	s->tbuflen = 0;
+	s->secret = nil;
 	fss->ps = s;
 	return RpcOk;
 }
@@ -147,13 +149,12 @@
 		m = TICKREQLEN;
 		if(*n < m)
 			return toosmall(fss, m);
-		*n = m;
-		convTR2M(&s->tr, a);
+		*n = convTR2M(&s->tr, a, *n);
 		fss->phase = SNeedTicket;
 		return RpcOk;
 
 	case CHaveTicket:
-		m = TICKETLEN+AUTHENTLEN;
+		m = s->tbuflen;
 		if(*n < m)
 			return toosmall(fss, m);
 		*n = m;
@@ -162,11 +163,11 @@
 		return RpcOk;
 
 	case SHaveAuth:
-		m = AUTHENTLEN;
+		m = s->tbuflen;
 		if(*n < m)
 			return toosmall(fss, m);
 		*n = m;
-		memmove(a, s->tbuf+TICKETLEN, m);
+		memmove(a, s->tbuf, m);
 		fss->ai.cuid = s->t.cuid;
 		fss->ai.suid = s->t.suid;
 		s->secret = emalloc(8);
@@ -183,7 +184,7 @@
 p9skwrite(Fsstate *fss, void *a, uint n)
 {
 	int m, ret, sret;
-	char tbuf[2*TICKETLEN], trbuf[TICKREQLEN], *user;
+	char tbuf[2*TICKETLEN], *user;
 	Attr *attr;
 	Authenticator auth;
 	State *s;
@@ -204,12 +205,11 @@
 		return RpcOk;
 
 	case CNeedTreq:
-		m = TICKREQLEN;
-		if(n < m)
-			return toosmall(fss, m);
+		m = convM2TR(a, n, &s->tr);
+		if(m <= 0)
+			return toosmall(fss, -m);
 
 		/* remember server's chal */
-		convM2TR(a, &s->tr);
 		if(s->vers == 2)
 			memmove(s->cchal, s->tr.chal, CHALLEN);
 
@@ -263,15 +263,14 @@
 		else
 			safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
 
-		convTR2M(&s->tr, trbuf);
-
 		/* get tickets, from auth server or invent if we can */
-		if(gettickets(s, trbuf, tbuf) < 0){
+		ret = gettickets(s, &s->tr, tbuf, sizeof(tbuf));
+		if(ret < 0){
 			_freeattr(attr);
 			return failure(fss, nil);
 		}
 
-		convM2T(tbuf, &s->t, (char*)s->key->priv);
+		m = convM2T(tbuf, ret, &s->t, (Authkey*)s->key->priv);
 		if(s->t.num != AuthTc){
 			if(s->key->successes == 0 && !s->speakfor)
 				disablekey(s->key);
@@ -287,24 +286,27 @@
 		}
 		s->key->successes++;
 		_freeattr(attr);
-		memmove(s->tbuf, tbuf+TICKETLEN, TICKETLEN);
+		ret -= m;
+		memmove(s->tbuf, tbuf+m, ret);
 
 		auth.num = AuthAc;
 		memmove(auth.chal, s->tr.chal, CHALLEN);
 		auth.id = 0;
-		convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
+		ret += convA2M(&auth, s->tbuf+ret, sizeof(s->tbuf)-ret, &s->t);
+		s->tbuflen = ret;
 		fss->phase = CHaveTicket;
 		return RpcOk;
 
 	case SNeedTicket:
-		m = TICKETLEN+AUTHENTLEN;
-		if(n < m)
-			return toosmall(fss, m);
-		convM2T(a, &s->t, (char*)s->key->priv);
+		m = convM2T(a, n, &s->t, (Authkey*)s->key->priv);
+		if(m <= 0)
+			return toosmall(fss, -m);
 		if(s->t.num != AuthTs
 		|| memcmp(s->t.chal, s->tr.chal, CHALLEN) != 0)
 			return failure(fss, Easproto);
-		convM2A((char*)a+TICKETLEN, &auth, s->t.key);
+		ret = convM2A((char*)a+m, n-m, &auth, &s->t);
+		if(ret <= 0)
+			return toosmall(fss, -ret + m);
 		if(auth.num != AuthAc
 		|| memcmp(auth.chal, s->tr.chal, CHALLEN) != 0
 		|| auth.id != 0)
@@ -312,15 +314,14 @@
 		auth.num = AuthAs;
 		memmove(auth.chal, s->cchal, CHALLEN);
 		auth.id = 0;
-		convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
+		s->tbuflen = convA2M(&auth, s->tbuf, sizeof(s->tbuf), &s->t);
 		fss->phase = SHaveAuth;
 		return RpcOk;
 
 	case CNeedAuth:
-		m = AUTHENTLEN;
-		if(n < m)
-			return toosmall(fss, m);
-		convM2A(a, &auth, s->t.key);
+		m = convM2A(a, n, &auth, &s->t);
+		if(m <= 0)
+			return toosmall(fss, -m);
 		if(auth.num != AuthAs
 		|| memcmp(auth.chal, s->cchal, CHALLEN) != 0
 		|| auth.id != 0)
@@ -384,24 +385,24 @@
 static int
 p9skaddkey(Key *k, int before)
 {
+	Authkey *akey;
 	char *s;
 
-	k->priv = emalloc(DESKEYLEN);
+	akey = emalloc(sizeof(Authkey));
 	if(s = _strfindattr(k->privattr, "!hex")){
-		if(hexparse(s, k->priv, 7) < 0){
-			free(k->priv);
-			k->priv = nil;
+		if(hexparse(s, (uchar*)akey->des, DESKEYLEN) < 0){
+			free(akey);
 			werrstr("malformed key data");
 			return -1;
 		}
 	}else if(s = _strfindattr(k->privattr, "!password")){
-		passtokey((char*)k->priv, s);
+		passtokey(akey, s);
 	}else{
 		werrstr("no key data");
-		free(k->priv);
-		k->priv = nil;
+		free(akey);
 		return -1;
 	}
+	k->priv = akey;
 	return replacekey(k, before);
 }
 
@@ -412,7 +413,7 @@
 }
 
 static int
-getastickets(State *s, char *trbuf, char *tbuf)
+getastickets(State *s, Ticketreq *tr, char *tbuf, int tbuflen)
 {
 	int asfd, rv;
 	char *dom;
@@ -425,7 +426,7 @@
 	if(asfd < 0)
 		return -1;
 	alarm(30*1000);
-	rv = _asgetticket(asfd, trbuf, tbuf);
+	rv = _asgetticket(asfd, tr, tbuf, tbuflen);
 	alarm(0);
 	close(asfd);
 	return rv;
@@ -432,10 +433,11 @@
 }
 
 static int
-mkserverticket(State *s, char *tbuf)
+mkserverticket(State *s, char *tbuf, int tbuflen)
 {
 	Ticketreq *tr = &s->tr;
 	Ticket t;
+	int ret;
 
 	if(strcmp(tr->authid, tr->hostid) != 0)
 		return -1;
@@ -449,22 +451,21 @@
 	strcpy(t.suid, tr->uid);
 	memrandom(t.key, DESKEYLEN);
 	t.num = AuthTc;
-	convT2M(&t, tbuf, s->key->priv);
+	ret = convT2M(&t, tbuf, tbuflen, (Authkey*)s->key->priv);
 	t.num = AuthTs;
-	convT2M(&t, tbuf+TICKETLEN, s->key->priv);
-	return 0;
+	ret += convT2M(&t, tbuf+ret, tbuflen-ret, (Authkey*)s->key->priv);
+	return ret;
 }
 
 static int
-gettickets(State *s, char *trbuf, char *tbuf)
+gettickets(State *s, Ticketreq *tr, char *tbuf, int tbuflen)
 {
-/*
-	if(mktickets(s, trbuf, tbuf) >= 0)
-		return 0;
-*/
-	if(getastickets(s, trbuf, tbuf) >= 0)
-		return 0;
-	return mkserverticket(s, tbuf);
+	int ret;
+
+	ret = getastickets(s, tr, tbuf, tbuflen);
+	if(ret >= 0)
+		return ret;
+	return mkserverticket(s, tbuf, tbuflen);
 }
 
 Proto p9sk1 = {
--- a/sys/src/cmd/auth/guard.srv.c
+++ b/sys/src/cmd/auth/guard.srv.c
@@ -90,7 +90,7 @@
 
 	/* remove password login from guard.research.bell-labs.com, sucre, etc. */
 //	if(!findkey(KEYDB,    user, ukey) || !netcheck(ukey, chal, resp))
-	if(!findkey(NETKEYDB, user, ukey) || !netcheck(ukey, chal, resp))
+	if(!finddeskey(NETKEYDB, user, ukey) || !netcheck(ukey, chal, resp))
 	if((err = secureidcheck(user, resp)) != nil){
 		print("NO %s", err);
 		write(1, "NO", 2);
--- a/sys/src/cmd/auth/httpauth.c
+++ b/sys/src/cmd/auth/httpauth.c
@@ -8,36 +8,25 @@
 	int afd;
 	Ticketreq tr;
 	Ticket	t;
-	char key[DESKEYLEN];
-	char buf[512];
+	Authkey key;
 
 	afd = authdial(nil, nil);
 	if(afd < 0)
 		return -1;
 
+	passtokey(&key, password);
+
 	/* send ticket request to AS */
 	memset(&tr, 0, sizeof(tr));
 	strcpy(tr.uid, name);
 	tr.type = AuthHttp;
-	convTR2M(&tr, buf);
-	if(write(afd, buf, TICKREQLEN) != TICKREQLEN){
+	if(_asrequest(afd, &tr) < 0){
 		close(afd);
 		return -1;
 	}
-	if(_asrdresp(afd, buf, TICKETLEN) < 0){
-		close(afd);
-		return -1;
-	}
+	_asgetresp(afd, &t, nil, &key);
 	close(afd);
-
-	/*
-	 *  use password and try to decrypt the
-	 *  ticket.  If it doesn't work we've got a bad password,
-	 *  give up.
-	 */
-	passtokey(key, password);
-	convM2T(buf, &t, key);
-	if(t.num != AuthHr || strcmp(t.cuid, tr.uid))
+	if(t.num != AuthHr || strcmp(t.cuid, tr.uid) != 0)
 		return -1;
 
 	return 0;
--- a/sys/src/cmd/auth/keyfs.c
+++ b/sys/src/cmd/auth/keyfs.c
@@ -13,7 +13,7 @@
 
 #pragma	varargck	type	"W"	char*
 
-char authkey[8];
+Authkey authkey;
 
 typedef struct Fid	Fid;
 typedef struct User	User;
@@ -170,9 +170,9 @@
 		error("can't make pipe: %r");
 
 	if(usepass) {
-		getpass(authkey, nil, 0, 0);
+		getpass(&authkey, nil, 0, 0);
 	} else {
-		if(!getauthkey(authkey))
+		if(!getauthkey(&authkey))
 			print("keyfs: warning: can't read NVRAM\n");
 	}
 
@@ -690,7 +690,7 @@
 
 	if(Bread(b, buf, KEYDBLEN) != KEYDBLEN)
 		return 0;
-	decrypt(authkey, buf, KEYDBLEN);
+	decrypt(authkey.des, buf, KEYDBLEN);
 	buf[Namelen-1] = '\0';
 	return 1;
 }
@@ -780,7 +780,7 @@
 		}
 
 	/* encrypt */
-	oldCBCencrypt(authkey, buf, p - buf);
+	oldCBCencrypt(authkey.des, buf, p - buf);
 
 	/* write file */
 	fd = create(userkeys, OWRITE, 0660);
@@ -888,7 +888,7 @@
 
 	/* decrypt */
 	n -= n % KEYDBLEN;
-	oldCBCdecrypt(authkey, buf, n);
+	oldCBCdecrypt(authkey.des, buf, n);
 
 	/* unpack */
 	nu = 0;
--- a/sys/src/cmd/auth/lib/error.c
+++ b/sys/src/cmd/auth/lib/error.c
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 void
--- a/sys/src/cmd/auth/lib/fs.c
+++ b/sys/src/cmd/auth/lib/fs.c
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 Fs fs[3] =
--- a/sys/src/cmd/auth/lib/getauthkey.c
+++ b/sys/src/cmd/auth/lib/getauthkey.c
@@ -17,9 +17,10 @@
 }
 
 int
-getauthkey(char *authkey)
+getauthkey(Authkey *authkey)
 {
-	if(getkey(authkey) == 0)
+	memset(authkey, 0, sizeof(Authkey));
+	if(getkey(authkey->des) == 0)
 		return 1;
 	print("can't read NVRAM, please enter machine key\n");
 	getpass(authkey, nil, 0, 1);
--- a/sys/src/cmd/auth/lib/getexpiration.c
+++ b/sys/src/cmd/auth/lib/getexpiration.c
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <ctype.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 /*
--- a/sys/src/cmd/auth/lib/keyfmt.c
+++ b/sys/src/cmd/auth/lib/keyfmt.c
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 /*
@@ -7,7 +8,7 @@
  * print a key in des standard form
  */
 int
-keyfmt(Fmt *f)
+deskeyfmt(Fmt *f)
 {
 	uchar key[8];
 	char buf[32];
--- a/sys/src/cmd/auth/lib/netcheck.c
+++ b/sys/src/cmd/auth/lib/netcheck.c
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 /*
--- a/sys/src/cmd/auth/lib/querybio.c
+++ b/sys/src/cmd/auth/lib/querybio.c
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <bio.h>
 #include <ctype.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 
--- a/sys/src/cmd/auth/lib/rdbio.c
+++ b/sys/src/cmd/auth/lib/rdbio.c
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <bio.h>
 #include <ctype.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 void
--- a/sys/src/cmd/auth/lib/readarg.c
+++ b/sys/src/cmd/auth/lib/readarg.c
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 int
--- a/sys/src/cmd/auth/lib/readln.c
+++ b/sys/src/cmd/auth/lib/readln.c
@@ -5,7 +5,7 @@
 #include "authcmdlib.h"
 
 void
-getpass(char *key, char *pass, int check, int confirm)
+getpass(Authkey *key, char *pass, int check, int confirm)
 {
 	char rpass[32], npass[32];
 	char *err;
--- a/sys/src/cmd/auth/lib/readwrite.c
+++ b/sys/src/cmd/auth/lib/readwrite.c
@@ -33,7 +33,7 @@
 }
 
 char*
-findkey(char *db, char *user, char *key)
+finddeskey(char *db, char *user, char *key)
 {
 	int n;
 	char filename[Maxpath];
@@ -46,6 +46,13 @@
 		return key;
 }
 
+int
+findkey(char *db, char *user, Authkey *key)
+{
+	memset(key, 0, sizeof(Authkey));
+	return finddeskey(db, user, key->des) != nil;
+}
+
 char*
 findsecret(char *db, char *user, char *secret)
 {
@@ -62,7 +69,7 @@
 }
 
 char*
-setkey(char *db, char *user, char *key)
+setdeskey(char *db, char *user, char *key)
 {
 	int n;
 	char filename[Maxpath];
@@ -73,6 +80,12 @@
 		return 0;
 	else
 		return key;
+}
+
+int
+setkey(char *db, char *user, Authkey *key)
+{
+	return setdeskey(db, user, key->des) != nil;
 }
 
 char*
--- a/sys/src/cmd/auth/lib/wrbio.c
+++ b/sys/src/cmd/auth/lib/wrbio.c
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <bio.h>
 #include <ctype.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 void
--- a/sys/src/cmd/auth/netkey.c
+++ b/sys/src/cmd/auth/netkey.c
@@ -15,7 +15,8 @@
 void
 main(int argc, char *argv[])
 {
-	char buf[32], pass[32], key[DESKEYLEN];
+	Authkey key;
+	char buf[32], pass[32];
 	char *s;
 	int n;
 
@@ -33,7 +34,7 @@
 	}
 
 	readln("Password: ", pass, sizeof pass, 1);
-	passtokey(key, pass);
+	passtokey(&key, pass);
 
 	for(;;){
 		print("challenge: ");
@@ -43,7 +44,7 @@
 		buf[n] = '\0';
 		n = strtol(buf, 0, 10);
 		sprint(buf, "%d", n);
-		netcrypt(key, buf);
+		netcrypt(key.des, buf);
 		print("response: %s\n", buf);
 	}
 }
--- a/sys/src/cmd/auth/passwd.c
+++ b/sys/src/cmd/auth/passwd.c
@@ -1,52 +1,17 @@
 #include <u.h>
 #include <libc.h>
-#include <authsrv.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
-static char *pbmsg = "AS protocol botch";
-
-int
-asrdresp(int fd, char *buf, int len)
-{
-	char error[AERRLEN];
-
-	if(read(fd, buf, 1) != 1){
-		werrstr(pbmsg);
-		return -1;
-	}
-
-	switch(buf[0]){
-	case AuthOK:
-		if(readn(fd, buf, len) < 0){
-			werrstr(pbmsg);
-			return -1;
-		}
-		break;
-	case AuthErr:
-		if(readn(fd, error, AERRLEN) < 0){
-			werrstr(pbmsg);
-			return -1;
-		}
-		error[AERRLEN-1] = 0;
-		errstr(error, sizeof error);
-		return -1;
-	default:
-		werrstr(pbmsg);
-		return -1;
-	}
-	return 0;
-}
-
 void
 main(int argc, char **argv)
 {
-	int fd;
+	int fd, n;
 	Ticketreq tr;
 	Ticket t;
 	Passwordreq pr;
-	char tbuf[TICKETLEN];
-	char key[DESKEYLEN];
+	Authkey key;
 	char buf[512];
 	char *s, *user;
 
@@ -73,12 +38,8 @@
 	memset(&tr, 0, sizeof(tr));
 	strcpy(tr.uid, user);
 	tr.type = AuthPass;
-	convTR2M(&tr, buf);
-	if(write(fd, buf, TICKREQLEN) != TICKREQLEN)
-		error("protocol botch: %r");
-	if(asrdresp(fd, buf, TICKETLEN) < 0)
+	if(_asrequest(fd, &tr) < 0)
 		error("%r");
-	memmove(tbuf, buf, TICKETLEN);
 
 	/*
 	 *  get a password from the user and try to decrypt the
@@ -86,13 +47,17 @@
 	 *  give up.
 	 */
 	readln("Plan 9 Password: ", pr.old, sizeof pr.old, 1);
-	passtokey(key, pr.old);
-	convM2T(tbuf, &t, key);
-	if(t.num != AuthTp || strcmp(t.cuid, tr.uid))
+	passtokey(&key, pr.old);
+
+	if(_asgetresp(fd, &t, nil, &key) < 0)
+		error("%r");
+
+	if(t.num != AuthTp || strcmp(t.cuid, tr.uid) != 0)
 		error("bad password");
 
 	/* loop trying new passwords */
 	for(;;){
+		memset(&pr, 0, sizeof(pr));
 		pr.changesecret = 0;
 		*pr.new = 0;
 		readln("change Plan 9 Password? (y/n) ", buf, sizeof buf, 0);
@@ -126,10 +91,10 @@
 			}
 		}
 		pr.num = AuthPass;
-		convPR2M(&pr, buf, t.key);
-		if(write(fd, buf, PASSREQLEN) != PASSREQLEN)
+		n = convPR2M(&pr, buf, sizeof(buf), &t);
+		if(write(fd, buf, n) != n)
 			error("AS protocol botch: %r");
-		if(asrdresp(fd, buf, 0) == 0)
+		if(_asrdresp(fd, buf, 0) == 0)
 			break;
 		fprint(2, "passwd: refused: %r\n");
 	}
--- a/sys/src/cmd/auth/printnetkey.c
+++ b/sys/src/cmd/auth/printnetkey.c
@@ -1,10 +1,9 @@
 #include <u.h>
 #include <libc.h>
-#include <authsrv.h>
 #include <bio.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
-void	install(char*, char*, int);
 void	usage(void);
 
 void
@@ -15,7 +14,7 @@
 	char keybuf[DESKEYLEN];
 
 	argv0 = "printnetkey";
-	fmtinstall('K', keyfmt);
+	fmtinstall('K', deskeyfmt);
 
 	ARGBEGIN{
 	default:
@@ -25,11 +24,9 @@
 		usage();
 
 	u = argv[0];
-	fmtinstall('K', keyfmt);
-	
 	if(memchr(u, '\0', ANAMELEN) == 0)
 		error("bad user name");
-	key = findkey(NETKEYDB, u, keybuf);
+	key = finddeskey(NETKEYDB, u, keybuf);
 	if(!key)
 		error("%s has no netkey\n", u);
 	print("user %s: net key %K\n", u, key);
--- a/sys/src/cmd/auth/warning.c
+++ b/sys/src/cmd/auth/warning.c
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <bio.h>
 #include <auth.h>
+#include <authsrv.h>
 #include "authcmdlib.h"
 
 /* working directory */
--- a/sys/src/libauth/auth_userpasswd.c
+++ b/sys/src/libauth/auth_userpasswd.c
@@ -11,13 +11,13 @@
  * this was copied from inet's guard.
  */
 static void
-netresp(char *key, long chal, char *answer)
+netresp(Authkey *key, long chal, char *answer)
 {
 	uchar buf[8];
 
 	memset(buf, 0, sizeof buf);
 	snprint((char *)buf, sizeof buf, "%lud", chal);
-	if(encrypt(key, buf, 8) < 0)
+	if(encrypt(key->des, buf, 8) < 0)
 		abort();
 	sprint(answer, "%.8ux", buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]);
 }
@@ -25,7 +25,8 @@
 AuthInfo*
 auth_userpasswd(char *user, char *passwd)
 {
-	char key[DESKEYLEN], resp[16];
+	char resp[16];
+	Authkey key;
 	AuthInfo *ai;
 	Chalstate *ch;
 
@@ -37,9 +38,9 @@
 	if((ch = auth_challenge("user=%q proto=p9cr role=server", user)) == nil)
 		return nil;
 
-	passtokey(key, passwd);
-	netresp(key, atol(ch->chal), resp);
-	memset(key, 0, sizeof key);
+	passtokey(&key, passwd);
+	netresp(&key, atol(ch->chal), resp);
+	memset(&key, 0, sizeof(Authkey));
 
 	ch->resp = resp;
 	ch->nresp = strlen(resp);
--- a/sys/src/libauth/httpauth.c
+++ /dev/null
@@ -1,51 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <authsrv.h>
-
-/* deprecated.
-	This is the mechanism that put entries in /sys/lib/httpd.rewrite
-	and passwords on the authserver in /sys/lib/httppasswords, which
-	was awkward to administer.  Instead, use local .httplogin files,
-	which are implemented in sys/src/cmd/ip/httpd/authorize.c */
-
-int
-httpauth(char *name, char *password)
-{
-	int afd;
-	Ticketreq tr;
-	Ticket	t;
-	char key[DESKEYLEN];
-	char buf[512];
-
-	afd = authdial(nil, nil);
-	if(afd < 0)
-		return -1;
-
-	/* send ticket request to AS */
-	memset(&tr, 0, sizeof(tr));
-	strcpy(tr.uid, name);
-	tr.type = AuthHttp;
-	convTR2M(&tr, buf);
-	if(write(afd, buf, TICKREQLEN) != TICKREQLEN){
-		close(afd);
-		return -1;
-	}
-	if(_asrdresp(afd, buf, TICKETLEN) < 0){
-		close(afd);
-		return -1;
-	}
-	close(afd);
-
-	/*
-	 *  use password and try to decrypt the
-	 *  ticket.  If it doesn't work we've got a bad password,
-	 *  give up.
-	 */
-	passtokey(key, password);
-	convM2T(buf, &t, key);
-	if(t.num != AuthHr || strcmp(t.cuid, tr.uid))
-		return -1;
-
-	return 0;
-}
--- a/sys/src/libauthsrv/_asgetticket.c
+++ b/sys/src/libauthsrv/_asgetticket.c
@@ -5,11 +5,13 @@
 static char *pbmsg = "AS protocol botch";
 
 int
-_asgetticket(int fd, char *trbuf, char *tbuf)
+_asgetticket(int fd, Ticketreq *tr, char *tbuf, int tbuflen)
 {
-	if(write(fd, trbuf, TICKREQLEN) < 0){
+	if(_asrequest(fd, tr) < 0){
 		werrstr(pbmsg);
 		return -1;
 	}
-	return _asrdresp(fd, tbuf, 2*TICKETLEN);
+	if(tbuflen > 2*TICKETLEN)
+		tbuflen = 2*TICKETLEN;
+	return _asrdresp(fd, tbuf, tbuflen);
 }
--- a/sys/src/libauthsrv/convA2M.c
+++ b/sys/src/libauthsrv/convA2M.c
@@ -9,17 +9,19 @@
 #define	STRING(x,n)	memmove(p, f->x, n); p += n
 
 int
-convA2M(Authenticator *f, char *ap, char *key)
+convA2M(Authenticator *f, char *ap, int n, Ticket *t)
 {
-	int n;
 	uchar *p;
 
+	if(n < AUTHENTLEN)
+		return 0;
+
 	p = (uchar*)ap;
 	CHAR(num);
 	STRING(chal, CHALLEN);
 	LONG(id);
 	n = p - (uchar*)ap;
-	if(key)
-		encrypt(key, ap, n);
+	if(t)
+		encrypt(t->key, ap, n);
 	return n;
 }
--- a/sys/src/libauthsrv/convM2A.c
+++ b/sys/src/libauthsrv/convM2A.c
@@ -8,16 +8,24 @@
 #define	LONG(x)		VLONG(f->x)
 #define	STRING(x,n)	memmove(f->x, p, n); p += n
 
-void
-convM2A(char *ap, Authenticator *f, char *key)
+int
+convM2A(char *ap, int n, Authenticator *f, Ticket *t)
 {
-	uchar *p;
+	uchar *p, buf[AUTHENTLEN];
 
-	if(key)
-		decrypt(key, ap, AUTHENTLEN);
+	memset(f, 0, sizeof(Authenticator));
+	if(n < AUTHENTLEN)
+		return -AUTHENTLEN;
+
+	if(t) {
+		memmove(buf, ap, AUTHENTLEN);
+		ap = (char*)buf;
+		decrypt(t->key, ap, AUTHENTLEN);
+	}
 	p = (uchar*)ap;
 	CHAR(num);
 	STRING(chal, CHALLEN);
 	LONG(id);
-	USED(p);
+	n = p - (uchar*)ap;
+	return n;
 }
--- a/sys/src/libauthsrv/convM2PR.c
+++ b/sys/src/libauthsrv/convM2PR.c
@@ -8,14 +8,21 @@
 #define	LONG(x)		VLONG(f->x)
 #define	STRING(x,n)	memmove(f->x, p, n); p += n
 
-void
-convM2PR(char *ap, Passwordreq *f, char *key)
+int
+convM2PR(char *ap, int n, Passwordreq *f, Ticket *t)
 {
-	uchar *p;
+	uchar *p, buf[PASSREQLEN];
 
+	memset(f, 0, sizeof(Passwordreq));
+	if(n < PASSREQLEN)
+		return -PASSREQLEN;
+
+	if(t){
+		memmove(buf, ap, PASSREQLEN);
+		ap = (char*)buf;
+		decrypt(t->key, ap, PASSREQLEN);
+	}
 	p = (uchar*)ap;
-	if(key)
-		decrypt(key, ap, PASSREQLEN);
 	CHAR(num);
 	STRING(old, ANAMELEN);
 	f->old[ANAMELEN-1] = 0;
@@ -24,5 +31,6 @@
 	CHAR(changesecret);
 	STRING(secret, SECRETLEN);
 	f->secret[SECRETLEN-1] = 0;
-	USED(p);
+	n = p - (uchar*)ap;
+	return n;
 }
--- a/sys/src/libauthsrv/convM2T.c
+++ b/sys/src/libauthsrv/convM2T.c
@@ -8,13 +8,20 @@
 #define	LONG(x)		VLONG(f->x)
 #define	STRING(x,n)	memmove(f->x, p, n); p += n
 
-void
-convM2T(char *ap, Ticket *f, char *key)
+int
+convM2T(char *ap, int n, Ticket *f, Authkey *key)
 {
-	uchar *p;
+	uchar *p, buf[TICKETLEN];
 
-	if(key)
-		decrypt(key, ap, TICKETLEN);
+	memset(f, 0, sizeof(Ticket));
+	if(n < TICKETLEN)
+		return -TICKETLEN;
+
+	if(key){
+		memmove(buf, ap, TICKETLEN);
+		ap = (char*)buf;
+		decrypt(key->des, ap, TICKETLEN);
+	}
 	p = (uchar*)ap;
 	CHAR(num);
 	STRING(chal, CHALLEN);
@@ -23,6 +30,6 @@
 	STRING(suid, ANAMELEN);
 	f->suid[ANAMELEN-1] = 0;
 	STRING(key, DESKEYLEN);
-	USED(p);
+	n = p - (uchar*)ap;
+	return n;
 }
-
--- a/sys/src/libauthsrv/convM2TR.c
+++ b/sys/src/libauthsrv/convM2TR.c
@@ -8,11 +8,15 @@
 #define	LONG(x)		VLONG(f->x)
 #define	STRING(x,n)	memmove(f->x, p, n); p += n
 
-void
-convM2TR(char *ap, Ticketreq *f)
+int
+convM2TR(char *ap, int n, Ticketreq *f)
 {
 	uchar *p;
 
+	memset(f, 0, sizeof(Ticketreq));
+	if(n < TICKREQLEN)
+		return -TICKREQLEN;
+
 	p = (uchar*)ap;
 	CHAR(type);
 	STRING(authid, ANAMELEN);
@@ -24,5 +28,6 @@
 	f->hostid[ANAMELEN-1] = 0;
 	STRING(uid, ANAMELEN);
 	f->uid[ANAMELEN-1] = 0;
-	USED(p);
+	n = p - (uchar*)ap;
+	return n;
 }
--- a/sys/src/libauthsrv/convPR2M.c
+++ b/sys/src/libauthsrv/convPR2M.c
@@ -9,11 +9,13 @@
 #define	STRING(x,n)	memmove(p, f->x, n); p += n
 
 int
-convPR2M(Passwordreq *f, char *ap, char *key)
+convPR2M(Passwordreq *f, char *ap, int n, Ticket *t)
 {
-	int n;
 	uchar *p;
 
+	if(n < PASSREQLEN)
+		return 0;
+
 	p = (uchar*)ap;
 	CHAR(num);
 	STRING(old, ANAMELEN);
@@ -21,8 +23,8 @@
 	CHAR(changesecret);
 	STRING(secret, SECRETLEN);
 	n = p - (uchar*)ap;
-	if(key)
-		encrypt(key, ap, n);
+	if(t)
+		encrypt(t->key, ap, n);
 	return n;
 }
 
--- a/sys/src/libauthsrv/convT2M.c
+++ b/sys/src/libauthsrv/convT2M.c
@@ -9,11 +9,13 @@
 #define	STRING(x,n)	memmove(p, f->x, n); p += n
 
 int
-convT2M(Ticket *f, char *ap, char *key)
+convT2M(Ticket *f, char *ap, int n, Authkey *key)
 {
-	int n;
 	uchar *p;
 
+	if(n < TICKETLEN)
+		return 0;
+
 	p = (uchar*)ap;
 	CHAR(num);
 	STRING(chal, CHALLEN);
@@ -22,6 +24,6 @@
 	STRING(key, DESKEYLEN);
 	n = p - (uchar*)ap;
 	if(key)
-		encrypt(key, ap, n);
+		encrypt(key->des, ap, n);
 	return n;
 }
--- a/sys/src/libauthsrv/convTR2M.c
+++ b/sys/src/libauthsrv/convTR2M.c
@@ -9,11 +9,13 @@
 #define	STRING(x,n)	memmove(p, f->x, n); p += n
 
 int
-convTR2M(Ticketreq *f, char *ap)
+convTR2M(Ticketreq *f, char *ap, int n)
 {
-	int n;
 	uchar *p;
 
+	if(n < TICKREQLEN)
+		return 0;
+
 	p = (uchar*)ap;
 	CHAR(type);
 	STRING(authid, 28);	/* BUG */
@@ -24,4 +26,3 @@
 	n = p - (uchar*)ap;
 	return n;
 }
-
--- a/sys/src/libauthsrv/mkfile
+++ b/sys/src/libauthsrv/mkfile
@@ -3,6 +3,8 @@
 LIB=/$objtype/lib/libauthsrv.a
 OFILES=\
 	_asgetticket.$O\
+	_asgetresp.$O\
+	_asrequest.$O\
 	_asrdresp.$O\
 	authdial.$O\
 	convA2M.$O\
--- a/sys/src/libauthsrv/passtokey.c
+++ b/sys/src/libauthsrv/passtokey.c
@@ -3,7 +3,7 @@
 #include <authsrv.h>
 
 int
-passtokey(char *key, char *p)
+passtokey(Authkey *key, char *p)
 {
 	uchar buf[ANAMELEN], *t;
 	int i, n;
@@ -15,10 +15,10 @@
 	t = buf;
 	strncpy((char*)t, p, n);
 	t[n] = 0;
-	memset(key, 0, DESKEYLEN);
+	memset(key, 0, sizeof(Authkey));
 	for(;;){
 		for(i = 0; i < DESKEYLEN; i++)
-			key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
+			key->des[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
 		if(n <= 8)
 			return 1;
 		n -= 8;
@@ -27,6 +27,6 @@
 			t -= 8 - n;
 			n = 8;
 		}
-		encrypt(key, t, 8);
+		encrypt(key->des, t, 8);
 	}
 }
--- a/sys/src/libauthsrv/readnvram.c
+++ b/sys/src/libauthsrv/readnvram.c
@@ -292,11 +292,14 @@
 			readcons("secstore key", nil, 1, safe->config,
 					sizeof safe->config);
 			for(;;){
-				if(readcons("password", nil, 1, in, sizeof in)
-				    == nil)
+				Authkey k;
+
+				if(readcons("password", nil, 1, in, sizeof in) == nil)
 					goto Out;
-				if(passtokey(safe->machkey, in))
+				if(passtokey(&k, in)){
+					memmove(safe->machkey, k.des, DESKEYLEN);
 					break;
+				}
 			}
 		}