shithub: riscv

Download patch

ref: 63b18e79252845d09abbad44672eabd9233a911b
parent: e48a5832b26f817ab06db2d42f88288373b78fac
author: cinap_lenrek <[email protected]>
date: Thu Aug 20 22:43:31 EDT 2015

introduce AES key into nvram and keyfs

--- a/sys/include/authsrv.h
+++ b/sys/include/authsrv.h
@@ -20,6 +20,7 @@
 	AERRLEN=	64,	/* errstr max size in previous proto */
 	DOMLEN=		48,	/* authentication domain name length */
 	DESKEYLEN=	7,	/* encrypt/decrypt des key length */
+	AESKEYLEN=	16,
 	CHALLEN=	8,	/* plan9 sk1 challenge length */
 	NETCHLEN=	16,	/* max network challenge length (used in AS protocol) */
 	CONFIGLEN=	14,
@@ -115,6 +116,7 @@
 struct	Authkey
 {
 	char	des[DESKEYLEN];
+	uchar	aes[AESKEYLEN];
 };
 
 /*
@@ -132,7 +134,7 @@
 /*
  *  convert ascii password to DES key
  */
-extern	int	passtokey(Authkey*, char*);
+extern	void	passtokey(Authkey*, char*);
 
 /*
  *  Nvram interface
@@ -147,7 +149,7 @@
 /* storage layout */
 struct Nvrsafe
 {
-	char	machkey[DESKEYLEN];	/* was file server's authid's des key */
+	char	machkey[DESKEYLEN];	/* file server's authid's des key */
 	uchar	machsum;
 	char	authkey[DESKEYLEN];	/* authid's des key from password */
 	uchar	authsum;
@@ -159,8 +161,11 @@
 	uchar	configsum;
 	char	authid[ANAMELEN];	/* auth userid, e.g., bootes */
 	uchar	authidsum;
-	char	authdom[DOMLEN]; /* auth domain, e.g., cs.bell-labs.com */
+	char	authdom[DOMLEN];	/* auth domain, e.g., cs.bell-labs.com */
 	uchar	authdomsum;
+
+	uchar	aesmachkey[AESKEYLEN];
+	uchar	aesmachsum;
 };
 
 extern	uchar	nvcsum(void*, int);
--- a/sys/man/2/authsrv
+++ b/sys/man/2/authsrv
@@ -15,7 +15,7 @@
 int	authdial(char *netroot, char *ad);
 .PP
 .B
-int	passtokey(Authkey *key, char *password)
+void	passtokey(Authkey *key, char *password)
 .PP
 .B
 uchar	nvcsum(void *mem, int len)
@@ -109,10 +109,6 @@
 .I Authkey
 structure
 .IR key .
-It returns 0 if
-.I password
-could not be converted,
-and 1 otherwise.
 .PP
 .I Readnvram
 reads authentication information into the structure:
--- a/sys/man/4/keyfs
+++ b/sys/man/4/keyfs
@@ -41,7 +41,7 @@
 .I keyfile
 (default
 .BR /adm/keys )
-using the DES key,
+using the DES or AES key,
 which is by default read from
 .B #r/nvram
 (see
@@ -51,13 +51,14 @@
 .I keyfs
 prompts for a password from which the key is derived.
 .I Keyfile
-holds a 41-byte record for each user in the database.
-Each record is encrypted separately
-and contains the user's name,
+holds a 41-byte (57-byte for AES) record for each user in the database.
+Each record contains the user's name,
 DES key,
 status,
-host status,
-and expiration date.
+warning status,
+expiration date,
+secret password
+and AES key.
 The name is a
 null-terminated
 .SM UTF
@@ -67,14 +68,18 @@
 The status is a byte containing
 binary 0 if the account is enabled,
 1 if it is disabled.
-Host status is a byte containing
-binary 1 if the user is a host,
-0 otherwise.
+Warning status is a byte containing
+the number of user expiration notifications.
 The expiration date is four-byte little-endian integer
 which represents the time in seconds since the epoch
 (see
 .IR date (1))
 at which the account will expire.
+The secret password is a null-terminated
+.SM UTF
+string
+.B SECRETLEN
+bytes long.
 If any changes are made to the database that affect the information stored in
 .IR keyfile ,
 a new version of the file is written.
@@ -111,6 +116,8 @@
 .PP
 All files in the user directories except for
 .B key
+and
+.B aeskey
 contain
 .SM UTF
 strings with a trailing newline when read,
@@ -121,6 +128,10 @@
 contains the
 .BR DESKEYLEN -byte
 encryption key for the user.
+.B Aeskey
+contains the
+.BR AESKEYLEN -byte
+encryption key.
 .PP
 The following files appear in the user directories.
 .TF expire
@@ -132,6 +143,12 @@
 Writing
 .I key
 changes the key in the database.
+.TP
+.B aeskey
+The AES encryption key for the user.
+.TP
+.B secret
+The secret password.
 .TP
 .B log
 The number of consecutive failed authentication attempts for the user.
--- a/sys/man/8/auth
+++ b/sys/man/8/auth
@@ -7,7 +7,7 @@
 .I user
 .PP
 .B auth/convkeys
-.RB [ -p ]
+.RB [ -pa ]
 .I keyfile
 .PP
 .B auth/convkeys2
@@ -151,6 +151,9 @@
 forces
 .I convkeys
 to also prompt for the old password.
+The
+.B -a
+option converts the file into AES format.
 The format of
 .I keyfile
 is described in
--- a/sys/src/cmd/auth/convkeys.c
+++ b/sys/src/cmd/auth/convkeys.c
@@ -7,11 +7,15 @@
 #include <bio.h>
 #include "authcmdlib.h"
 
-Authkey	authkey;
+Authkey	okey, nkey;
+
 int	verb;
 int	usepass;
+int	convaes;
 
-int	convert(char*, Authkey*, int);
+uchar	zeros[16];
+
+int	convert(char**, int);
 void	usage(void);
 
 void
@@ -18,7 +22,6 @@
 main(int argc, char *argv[])
 {
 	Dir *d;
-	Authkey key;
 	char *p, *file;
 	int fd, len;
 
@@ -29,6 +32,9 @@
 	case 'v':
 		verb = 1;
 		break;
+	case 'a':
+		convaes = 1;
+		break;
 	default:
 		usage();
 	}ARGEND
@@ -40,12 +46,13 @@
 	/* get original key */
 	if(usepass){
 		print("enter password file is encoded with\n");
-		getpass(&authkey, nil, 0, 1);
-	} else
-		getauthkey(&authkey);
+		getpass(&okey, nil, 0, 1);
+	} else {
+		getauthkey(&okey);
+	}
 	if(!verb){
 		print("enter password to reencode with\n");
-		getpass(&key, nil, 0, 1);
+		getpass(&nkey, nil, 0, 1);
 	}
 
 	fd = open(file, ORDWR);
@@ -56,17 +63,15 @@
 		error("can't stat %s: %r\n", file);
 	len = d->length;
 	p = malloc(len);
-	if(!p)
+	if(p == nil)
 		error("out of memory");
 	if(read(fd, p, len) != len)
 		error("can't read key file: %r\n");
-	len = convert(p, &key, len);
-	if(verb)
-		exits(0);
+	len = convert(&p, len);
 	if(pwrite(fd, p, len, 0) != len)
 		error("can't write key file: %r\n");
 	close(fd);
-	exits(0);
+	exits(nil);
 }
 
 void
@@ -76,7 +81,7 @@
 
 	fd = open("/dev/random", OREAD);
 	if(fd < 0){
-		fprint(2, "convkeys: can't open /dev/random, using rand()\n");
+		fprint(2, "%s: can't open /dev/random, using rand()\n", argv0);
 		srand(time(0));
 		for(i = 0; i < len; i++)
 			p[i] = rand();
@@ -86,34 +91,7 @@
 	close(fd);
 }
 
-void
-oldCBCencrypt(char *key7, char *p, int len)
-{
-	uchar ivec[8];
-	uchar key[8];
-	DESstate s;
-
-	memset(ivec, 0, 8);
-	des56to64((uchar*)key7, key);
-	setupDESstate(&s, key, ivec);
-	desCBCencrypt((uchar*)p, len, &s);
-}
-
-void
-oldCBCdecrypt(char *key7, char *p, int len)
-{
-	uchar ivec[8];
-	uchar key[8];
-	DESstate s;
-
-	memset(ivec, 0, 8);
-	des56to64((uchar*)key7, key);
-	setupDESstate(&s, key, ivec);
-	desCBCdecrypt((uchar*)p, len, &s);
-
-}
-
-static int
+int
 badname(char *s)
 {
 	int n;
@@ -128,29 +106,96 @@
 }
 
 int
-convert(char *p, Authkey *key, int len)
+convert(char **db, int len)
 {
-	int i;
+	int i, nu, keydblen, keydboff, keydbaes;
+	char *p = *db;
 
-	len -= KEYDBOFF;
-	if(len % KEYDBLEN){
-		fprint(2, "convkeys: file odd length; not converting %d bytes\n",
-			len % KEYDBLEN);
-		len -= len % KEYDBLEN;
+	keydblen = KEYDBLEN;
+	keydboff = KEYDBOFF;
+	keydbaes = len > 24 && memcmp(p, "AES KEYS", 8) == 0;
+	if(keydbaes){
+		keydblen += AESKEYLEN;
+		keydboff = 8+16;		/* signature[8] + iv[16] */
 	}
-	len += KEYDBOFF;
-	oldCBCdecrypt(authkey.des, p, len);
-	for(i = KEYDBOFF; i < len; i += KEYDBLEN)
+
+	len -= keydboff;
+	if(len % keydblen){
+		fprint(2, "%s: file odd length; not converting %d bytes\n", argv0, len % keydblen);
+		len -= len % keydblen;
+	}
+	len += keydboff;
+
+	if(keydbaes){
+		AESstate s;
+
+		/* make sure we have aes key for decryption */
+		if(memcmp(okey.aes, zeros, AESKEYLEN) == 0){
+			fprint(2, "%s: no aes key in NVRAM\n", argv0);
+			exits("no aes key");
+		}
+		setupAESstate(&s, okey.aes, AESKEYLEN, zeros);
+		aesCBCdecrypt((uchar*)p+8, len-8, &s);
+	} else {
+		DESstate s;
+		uchar k[8];
+
+		des56to64((uchar*)okey.des, k);
+		setupDESstate(&s, k, zeros);
+		desCBCdecrypt((uchar*)p, len, &s);
+	}
+
+	nu = 0;
+	for(i = keydboff; i < len; i += keydblen) {
 		if (badname(&p[i])) {
-			print("bad name %.30s... - aborting\n", &p[i]);
-			return 0;
+			fprint(2, "%s: bad name %.30s... - aborting\n", argv0, &p[i]);
+			exits("bad name");
 		}
-	if(verb)
-		for(i = KEYDBOFF; i < len; i += KEYDBLEN)
+		nu++;
+	}
+
+	if(verb){
+		for(i = keydboff; i < len; i += keydblen)
 			print("%s\n", &p[i]);
+		exits(nil);
+	}
 
-	randombytes((uchar*)p, 8);
-	oldCBCencrypt(key->des, p, len);
+	if(convaes && !keydbaes){
+		char *s, *d;
+
+		keydboff = 8+16;
+		keydblen += AESKEYLEN;
+		len = keydboff + keydblen*nu;
+		p = realloc(p, len);
+		if(p == nil)
+			error("out of memory");
+		*db = p;
+		s = p + KEYDBOFF + nu*KEYDBLEN;
+		d = p + keydboff + nu*keydblen;
+		for(i=0; i<nu; i++){
+			s -= KEYDBLEN;
+			d -= keydblen;
+			memmove(d, s, KEYDBLEN);
+			memset(d + KEYDBLEN, 0, keydblen-KEYDBLEN);
+		}
+		keydbaes = 1;
+	}
+
+	randombytes((uchar*)p, keydboff);
+	if(keydbaes){
+		AESstate s;
+
+		memmove(p, "AES KEYS", 8);
+		setupAESstate(&s, nkey.aes, AESKEYLEN, zeros);
+		aesCBCencrypt((uchar*)p+8, len-8, &s);
+	} else {
+		DESstate s;
+		uchar k[8];
+
+		des56to64((uchar*)nkey.des, k);
+		setupDESstate(&s, k, zeros);
+		desCBCencrypt((uchar*)p, len, &s);
+	}
 	return len;
 }
 
@@ -157,6 +202,6 @@
 void
 usage(void)
 {
-	fprint(2, "usage: convkeys keyfile\n");
+	fprint(2, "usage: %s [-pva] keyfile\n", argv0);
 	exits("usage");
 }
--- a/sys/src/cmd/auth/keyfs.c
+++ b/sys/src/cmd/auth/keyfs.c
@@ -14,6 +14,8 @@
 #pragma	varargck	type	"W"	char*
 
 Authkey authkey;
+int	keydbaes;
+uchar	zeros[16];
 
 typedef struct Fid	Fid;
 typedef struct User	User;
@@ -22,6 +24,7 @@
 	Qroot,
 	Quser,
 	Qkey,
+	Qaeskey,
 	Qsecret,
 	Qlog,
 	Qstatus,
@@ -52,6 +55,7 @@
 struct User {
 	char	*name;
 	char	key[DESKEYLEN];
+	uchar	aeskey[AESKEYLEN];
 	char	secret[SECRETLEN];
 	ulong	expire;			/* 0 == never */
 	uchar	status;
@@ -68,6 +72,7 @@
 	[Qroot]		"keys",
 	[Quser]		".",
 	[Qkey]		"key",
+	[Qaeskey]	"aeskey",
 	[Qsecret]	"secret",
 	[Qlog]		"log",
 	[Qexpire]	"expire",
@@ -85,8 +90,7 @@
 char	*userkeys;
 int	nuser;
 ulong	uniq = 1;
-Fcall	rhdr,
-	thdr;
+Fcall	rhdr, thdr;
 int	usepass;
 char	*warnarg;
 uchar	mdata[8192 + IOHDRSZ];
@@ -102,6 +106,7 @@
 void	writeusers(void);
 void	io(int, int);
 void	*emalloc(ulong);
+char	*estrdup(char*);
 Qid	mkqid(User*, ulong);
 int	dostat(User*, ulong, void*, int);
 int	newkeys(void);
@@ -136,6 +141,12 @@
 	exits("usage");
 }
 
+static int
+haveaeskey(void)
+{
+	return memcmp(authkey.aes, zeros, 16) != 0;
+}
+
 void
 main(int argc, char *argv[])
 {
@@ -169,13 +180,24 @@
 	if(pipe(p) < 0)
 		error("can't make pipe: %r");
 
-	if(usepass) {
+	if(usepass)
 		getpass(&authkey, nil, 0, 0);
-	} else {
+	else {
 		if(!getauthkey(&authkey))
-			print("keyfs: warning: can't read NVRAM\n");
+			fprint(2, "keyfs: warning: can't read NVRAM\n");
 	}
 
+	keydbaes = 0;
+	if(!newkeys() || !readusers()){
+		if(!keydbaes)
+			keydbaes = haveaeskey();
+		else if(!haveaeskey()){
+			fprint(2, "keyfs: no aes key in NVRAM\n");
+			getpass(&authkey, nil, 0, 0);
+			readusers();
+		}
+	}
+
 	switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){
 	case 0:
 		close(p[0]);
@@ -209,7 +231,7 @@
 {
 	if(f->busy)
 		Clunk(f);
-	f->user = 0;
+	f->user = nil;
 	f->qtype = Qroot;
 	f->busy = 1;
 	thdr.qid = mkqid(f->user, f->qtype);
@@ -272,7 +294,7 @@
 				if(strcmp(name, "..") == 0)
 					goto Accept;
 				user = finduser(name);
-				if(!user)
+				if(user == nil)
 					goto Out;
 				qtype = Quser;
 
@@ -283,7 +305,7 @@
 			case Quser:
 				if(strcmp(name, "..") == 0) {
 					qtype = Qroot;
-					user = 0;
+					user = nil;
 					goto Accept;
 				}
 				max = Qmax;
@@ -314,14 +336,16 @@
 	if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){
 		nf->busy = 1;
 		nf->qtype = qtype;
-		if(nf->user = user)
-			nf->user->ref++;
+		nf->user = user;
+		if(user != nil)
+			user->ref++;
 	}else if(nf == nil && rhdr.nwname > 0){	/* walk without clone (rare) */
 		Clunk(f);
 		f->busy = 1;
 		f->qtype = qtype;
-		if(f->user = user)
-			f->user->ref++;
+		f->user = user;
+		if(user != nil)
+			user->ref++;
 	}
 
 	thdr.nwqid = i;
@@ -332,12 +356,12 @@
 Clunk(Fid *f)
 {
 	f->busy = 0;
-	if(f->user && --f->user->ref == 0 && f->user->removed) {
+	if(f->user != nil && --f->user->ref == 0 && f->user->removed) {
 		free(f->user->name);
 		free(f->user);
 	}
-	f->user = 0;
-	return 0;
+	f->user = nil;
+	return nil;
 }
 
 char *
@@ -350,6 +374,8 @@
 	mode = rhdr.mode;
 	if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))
 		return "user already exists";
+	if(f->qtype == Qaeskey && !keydbaes)
+		return "keyfile not in aes format";
 	thdr.qid = mkqid(f->user, f->qtype);
 	thdr.iounit = messagesize - IOHDRSZ;
 	return 0;
@@ -364,7 +390,7 @@
 	if(!f->busy)
 		return "create of unused fid";
 	name = rhdr.name;
-	if(f->user){
+	if(f->user != nil){
 		return "permission denied";
 	}else{
 		perm = rhdr.perm;
@@ -374,7 +400,7 @@
 			return "empty file name";
 		if(strlen(name) >= Namelen)
 			return "file name too long";
-		if(finduser(name))
+		if(finduser(name) != nil)
 			return "user already exists";
 		f->user = installuser(name);
 		f->user->ref++;
@@ -404,7 +430,7 @@
 	case Qroot:
 		j = 0;
 		for(i = 0; i < Nuser; i++)
-			for(u = users[i]; u; j += m, u = u->link){
+			for(u = users[i]; u != nil; j += m, u = u->link){
 				m = dostat(u, Quser, data, n);
 				if(m <= BIT16SZ)
 					break;
@@ -431,19 +457,7 @@
 		thdr.count = data - thdr.data;
 		return 0;
 	case Qkey:
-		if(f->user->status != Sok)
-			return "user disabled";
-		if(f->user->purgatory > time(0))
-			return "user in purgatory";
-		if(f->user->expire != 0 && f->user->expire < time(0))
-			return "user expired";
-		if(off != 0)
-			return 0;
-		if(n > DESKEYLEN)
-			n = DESKEYLEN;
-		memmove(thdr.data, f->user->key, n);
-		thdr.count = n;
-		return 0;
+	case Qaeskey:
 	case Qsecret:
 		if(f->user->status != Sok)
 			return "user disabled";
@@ -451,57 +465,52 @@
 			return "user in purgatory";
 		if(f->user->expire != 0 && f->user->expire < time(0))
 			return "user expired";
-		if(off != 0)
-			return 0;
-		if(n > strlen(f->user->secret))
-			n = strlen(f->user->secret);
-		memmove(thdr.data, f->user->secret, n);
+		m = 0;
+		switch(f->qtype){
+		case Qkey:
+			data = f->user->key;
+			m = DESKEYLEN;
+			break;
+		case Qaeskey:
+			data = (char*)f->user->aeskey;
+			m = AESKEYLEN;
+			break;
+		case Qsecret:
+			data = f->user->secret;
+	Readstr:
+			m = strlen(data);
+			break;
+		}
+		if(off >= m)
+			n = 0;
+		else {
+			data += off;
+			m -= off;
+			if(n > m)
+				n = m;
+		}
+		if(data != thdr.data)
+			memmove(thdr.data, data, n);
 		thdr.count = n;
 		return 0;
 	case Qstatus:
-		if(off != 0){
-			thdr.count = 0;
-			return 0;
-		}
 		if(f->user->status == Sok && f->user->expire && f->user->expire < time(0))
-			sprint(thdr.data, "expired\n");
+			sprint(data, "expired\n");
 		else
-			sprint(thdr.data, "%s\n", status[f->user->status]);
-		thdr.count = strlen(thdr.data);
-		return 0;
+			sprint(data, "%s\n", status[f->user->status]);
+		goto Readstr;
 	case Qexpire:
-		if(off != 0){
-			thdr.count = 0;
-			return 0;
-		}
 		if(!f->user->expire)
 			strcpy(data, "never\n");
 		else
 			sprint(data, "%lud\n", f->user->expire);
-		if(n > strlen(data))
-			n = strlen(data);
-		thdr.count = n;
-		return 0;
+		goto Readstr;
 	case Qlog:
-		if(off != 0){
-			thdr.count = 0;
-			return 0;
-		}
 		sprint(data, "%lud\n", f->user->bad);
-		if(n > strlen(data))
-			n = strlen(data);
-		thdr.count = n;
-		return 0;
+		goto Readstr;
 	case Qwarnings:
-		if(off != 0){
-			thdr.count = 0;
-			return 0;
-		}
 		sprint(data, "%ud\n", f->user->warnings);
-		if(n > strlen(data))
-			n = strlen(data);
-		thdr.count = n;
-		return 0;
+		goto Readstr;
 	default:
 		return "permission denied: unknown qid";
 	}
@@ -525,11 +534,17 @@
 		memmove(f->user->key, data, DESKEYLEN);
 		thdr.count = DESKEYLEN;
 		break;
+	case Qaeskey:
+		if(n != AESKEYLEN)
+			return "garbled write data";
+		memmove(f->user->aeskey, data, AESKEYLEN);
+		thdr.count = AESKEYLEN;
+		break;
 	case Qsecret:
 		if(n >= SECRETLEN)
 			return "garbled write data";
 		memmove(f->user->secret, data, n);
-		f->user->secret[n] = 0;
+		f->user->secret[n] = '\0';
 		thdr.count = n;
 		break;
 	case Qstatus:
@@ -639,9 +654,7 @@
 	if(!removeuser(f->user))
 		return "user previously removed";
 	free(f->user->name);
-	f->user->name = strdup(d.name);
-	if(f->user->name == nil)
-		error("wstat: malloc failed: %r");
+	f->user->name = estrdup(d.name);
 	insertuser(f->user);
 	writeusers();
 	return 0;
@@ -683,18 +696,7 @@
 	return convD2M(&d, p, n);
 }
 
-int
-passline(Biobuf *b, void *vbuf)
-{
-	char *buf = vbuf;
 
-	if(Bread(b, buf, KEYDBLEN) != KEYDBLEN)
-		return 0;
-	decrypt(authkey.des, buf, KEYDBLEN);
-	buf[Namelen-1] = '\0';
-	return 1;
-}
-
 void
 randombytes(uchar *p, int len)
 {
@@ -713,57 +715,35 @@
 }
 
 void
-oldCBCencrypt(char *key7, uchar *p, int len)
-{
-	uchar ivec[8];
-	uchar key[8];
-	DESstate s;
-
-	memset(ivec, 0, 8);
-	des56to64((uchar*)key7, key);
-	setupDESstate(&s, key, ivec);
-	desCBCencrypt((uchar*)p, len, &s);
-}
-
-void
-oldCBCdecrypt(char *key7, uchar *p, int len)
-{
-	uchar ivec[8];
-	uchar key[8];
-	DESstate s;
-
-	memset(ivec, 0, 8);
-	des56to64((uchar*)key7, key);
-	setupDESstate(&s, key, ivec);
-	desCBCdecrypt((uchar*)p, len, &s);
-
-}
-
-void
 writeusers(void)
 {
+	int keydblen, keydboff;
 	int fd, i, nu;
 	User *u;
 	uchar *p, *buf;
 	ulong expire;
 
+	/* what format to use */
+	keydblen = KEYDBLEN;
+	keydboff = KEYDBOFF;
+	if(keydbaes){
+		keydblen += AESKEYLEN;
+		keydboff = 8+16;	/* segnature[8] + iv[16] */
+	}
+
 	/* count users */
 	nu = 0;
 	for(i = 0; i < Nuser; i++)
-		for(u = users[i]; u; u = u->link)
+		for(u = users[i]; u != nil; u = u->link)
 			nu++;
 
 	/* pack into buffer */
-	buf = malloc(KEYDBOFF + nu*KEYDBLEN);
-	if(buf == 0){
-		fprint(2, "keyfs: can't write keys file, out of memory\n");
-		return;
-	}
+	buf = emalloc(keydboff + nu*keydblen);
 	p = buf;
-	randombytes(p, KEYDBOFF);
-	p += KEYDBOFF;
+	randombytes(p, keydboff);
+	p += keydboff;
 	for(i = 0; i < Nuser; i++)
-		for(u = users[i]; u; u = u->link){
+		for(u = users[i]; u != nil; u = u->link){
 			strncpy((char*)p, u->name, Namelen);
 			p += Namelen;
 			memmove(p, u->key, DESKEYLEN);
@@ -777,11 +757,28 @@
 			*p++ = expire >> 24;
 			memmove(p, u->secret, SECRETLEN);
 			p += SECRETLEN;
+			if(keydbaes){
+				memmove(p, u->aeskey, AESKEYLEN);
+				p += AESKEYLEN;
+			}
 		}
 
 	/* encrypt */
-	oldCBCencrypt(authkey.des, buf, p - buf);
+	if(keydbaes){
+		AESstate s;
 
+		memmove(buf, "AES KEYS", 8);
+		setupAESstate(&s, authkey.aes, AESKEYLEN, zeros);
+		aesCBCencrypt(buf+8, (p - (buf+8)), &s);
+	} else {
+		uchar key[8];
+		DESstate s;
+
+		des56to64((uchar*)authkey.des, key);
+		setupDESstate(&s, key, zeros);
+		desCBCencrypt(buf, p - buf, &s);
+	}
+
 	/* write file */
 	fd = create(userkeys, OWRITE, 0660);
 	if(fd < 0){
@@ -858,6 +855,7 @@
 int
 readusers(void)
 {
+	int keydblen, keydboff;
 	int fd, i, n, nu;
 	uchar *p, *buf, *ep;
 	User *u;
@@ -872,12 +870,7 @@
 		close(fd);
 		return 0;
 	}
-	buf = malloc(d->length);
-	if(buf == 0){
-		close(fd);
-		free(d);
-		return 0;
-	}
+	buf = emalloc(d->length);
 	n = readn(fd, buf, d->length);
 	close(fd);
 	free(d);
@@ -886,18 +879,41 @@
 		return 0;
 	}
 
+	keydblen = KEYDBLEN;
+	keydboff = KEYDBOFF;
+	keydbaes = n > 24 && memcmp(buf, "AES KEYS", 8) == 0;
+
 	/* decrypt */
-	n -= n % KEYDBLEN;
-	oldCBCdecrypt(authkey.des, buf, n);
+	if(keydbaes){
+		AESstate s;
 
+		/* make sure we have AES encryption key */
+		if(!haveaeskey()){
+			free(buf);
+			return 0;
+		}
+		keydblen += AESKEYLEN;
+		keydboff = 8+16;	/* signature[8] + iv[16] */
+		setupAESstate(&s, authkey.aes, AESKEYLEN, zeros);
+		aesCBCdecrypt(buf+8, n-8, &s);
+	} else {
+		uchar key[8];
+		DESstate s;
+
+		des56to64((uchar*)authkey.des, key);
+		setupDESstate(&s, key, zeros);
+		desCBCdecrypt(buf, n, &s);
+	}
+
 	/* unpack */
 	nu = 0;
-	for(i = KEYDBOFF; i < n; i += KEYDBLEN){
-		ep = buf + i;
-		if(userok((char*)ep, i/KEYDBLEN) < 0)
+	n = (n - keydboff) / keydblen;
+	ep = buf + keydboff;
+	for(i = 0; i < n; ep += keydblen, i++){
+		if(userok((char*)ep, i) < 0)
 			continue;
 		u = finduser((char*)ep);
-		if(u == 0)
+		if(u == nil)
 			u = installuser((char*)ep);
 		memmove(u->key, ep + Namelen, DESKEYLEN);
 		p = ep + Namelen + DESKEYLEN;
@@ -909,11 +925,14 @@
 		p += 4;
 		memmove(u->secret, p, SECRETLEN);
 		u->secret[SECRETLEN-1] = 0;
+		p += SECRETLEN;
+		if(keydbaes)
+			memmove(u->aeskey, p, AESKEYLEN);
 		nu++;
 	}
 	free(buf);
 
-	print("%d keys read\n", nu);
+	print("%d keys read in %s foarmat\n", nu, keydbaes ? "AES" : "DES");
 	return 1;
 }
 
@@ -925,9 +944,7 @@
 
 	h = hash(name);
 	u = emalloc(sizeof *u);
-	u->name = strdup(name);
-	if(u->name == nil)
-		error("malloc failed: %r");
+	u->name = estrdup(name);
 	u->removed = 0;
 	u->ref = 0;
 	u->purgatory = 0;
@@ -946,10 +963,10 @@
 {
 	User *u;
 
-	for(u = users[hash(name)]; u; u = u->link)
+	for(u = users[hash(name)]; u != nil; u = u->link)
 		if(strcmp(name, u->name) == 0)
 			return u;
-	return 0;
+	return nil;
 }
 
 int
@@ -961,7 +978,7 @@
 	user->removed = 1;
 	name = user->name;
 	last = &users[hash(name)];
-	for(u = *last; u; u = *last){
+	for(u = *last; u != nil; u = *last){
 		if(strcmp(name, u->name) == 0){
 			*last = u->link;
 			return 1;
@@ -998,13 +1015,13 @@
 {
 	Fid *f, *ff;
 
-	ff = 0;
-	for(f = fids; f; f = f->next)
+	ff = nil;
+	for(f = fids; f != nil; f = f->next)
 		if(f->fid == fid)
 			return f;
 		else if(!ff && !f->busy)
 			ff = f;
-	if(ff){
+	if(ff != nil){
 		ff->fid = fid;
 		return ff;
 	}
@@ -1011,7 +1028,7 @@
 	f = emalloc(sizeof *f);
 	f->fid = fid;
 	f->busy = 0;
-	f->user = 0;
+	f->user = nil;
 	f->next = fids;
 	fids = f;
 	return f;
@@ -1088,10 +1105,24 @@
 {
 	void *p;
 
-	if(p = malloc(n))
+	if((p = malloc(n)) != nil){
+		memset(p, 0, n);
 		return p;
+	}
 	error("out of memory");
-	return 0;		/* not reached */
+	return nil;		/* not reached */
+}
+
+char *
+estrdup(char *s)
+{
+	char *d;
+	int n;
+
+	n = strlen(s)+1;
+	d = emalloc(n);
+	memmove(d, s, n);
+	return d;
 }
 
 void
--- a/sys/src/cmd/auth/lib/getauthkey.c
+++ b/sys/src/cmd/auth/lib/getauthkey.c
@@ -5,13 +5,14 @@
 #include "authcmdlib.h"
 
 static int
-getkey(char *authkey)
+getkey(Authkey *authkey)
 {
 	Nvrsafe safe;
 
 	if(readnvram(&safe, 0) < 0)
 		return -1;
-	memmove(authkey, safe.machkey, DESKEYLEN);
+	memmove(authkey->des, safe.machkey, DESKEYLEN);
+	memmove(authkey->aes, safe.aesmachkey, AESKEYLEN);
 	memset(&safe, 0, sizeof safe);
 	return 0;
 }
@@ -20,7 +21,7 @@
 getauthkey(Authkey *authkey)
 {
 	memset(authkey, 0, sizeof(Authkey));
-	if(getkey(authkey->des) == 0)
+	if(getkey(authkey) == 0)
 		return 1;
 	print("can't read NVRAM, please enter machine key\n");
 	getpass(authkey, nil, 0, 1);
--- a/sys/src/cmd/auth/lib/readln.c
+++ b/sys/src/cmd/auth/lib/readln.c
@@ -22,15 +22,12 @@
 				continue;
 			}
 		}
-		if(!passtokey(key, pass)){
-			print("bad password, try again\n");
-			continue;
-		}
 		if(check)
 			if(err = okpasswd(pass)){
 				print("%s, try again\n", err);
 				continue;
 			}
+		passtokey(key, pass);
 		break;
 	}
 }
--- a/sys/src/libauthsrv/passtokey.c
+++ b/sys/src/libauthsrv/passtokey.c
@@ -1,9 +1,10 @@
 #include <u.h>
 #include <libc.h>
 #include <authsrv.h>
+#include <libsec.h>
 
-int
-passtokey(Authkey *key, char *p)
+static void
+passtodeskey(char *key, char *p)
 {
 	uchar buf[ANAMELEN], *t;
 	int i, n;
@@ -15,12 +16,12 @@
 	t = buf;
 	strncpy((char*)t, p, n);
 	t[n] = 0;
-	memset(key, 0, sizeof(Authkey));
+	memset(key, 0, DESKEYLEN);
 	for(;;){
 		for(i = 0; i < DESKEYLEN; i++)
-			key->des[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
+			key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
 		if(n <= 8)
-			return 1;
+			return;
 		n -= 8;
 		t += 8;
 		if(n < 8){
@@ -27,6 +28,21 @@
 			t -= 8 - n;
 			n = 8;
 		}
-		encrypt(key->des, t, 8);
+		encrypt(key, t, 8);
 	}
+}
+
+static void
+passtoaeskey(uchar *key, char *p)
+{
+	static char salt[] = "Plan 9 key derivation";
+	pbkdf2_hmac_sha1((uchar*)p, strlen(p), (uchar*)salt, sizeof(salt)-1, 9001, key, AESKEYLEN);
+}
+
+void
+passtokey(Authkey *key, char *p)
+{
+	memset(key, 0, sizeof(Authkey));
+	passtodeskey(key->des, p);
+	passtoaeskey(key->aes, p);
 }
--- a/sys/src/libauthsrv/readnvram.c
+++ b/sys/src/libauthsrv/readnvram.c
@@ -268,13 +268,22 @@
 
 			/* verify data read */
 			err |= check(safe->machkey, DESKEYLEN, safe->machsum,
-						"bad nvram key");
-//			err |= check(safe->config, CONFIGLEN, safe->configsum,
-//						"bad secstore key");
+						"bad nvram des key");
 			err |= check(safe->authid, ANAMELEN, safe->authidsum,
 						"bad authentication id");
 			err |= check(safe->authdom, DOMLEN, safe->authdomsum,
 						"bad authentication domain");
+			if(0){
+				err |= check(safe->config, CONFIGLEN, safe->configsum,
+						"bad secstore key");
+				err |= check(safe->aesmachkey, AESKEYLEN, safe->aesmachsum,
+						"bad nvram aes key");
+			} else {
+				if(nvcsum(safe->config, CONFIGLEN) != safe->configsum)
+					memset(safe->config, 0, CONFIGLEN);
+				if(nvcsum(safe->aesmachkey, AESKEYLEN) != safe->aesmachsum)
+					memset(safe->aesmachkey, 0, AESKEYLEN);
+			}
 			if(err == 0)
 				if(safe->authid[0]==0 || safe->authdom[0]==0){
 					fprint(2, "empty nvram authid or authdom\n");
@@ -296,18 +305,19 @@
 
 				if(readcons("password", nil, 1, in, sizeof in) == nil)
 					goto Out;
-				if(passtokey(&k, in)){
-					memmove(safe->machkey, k.des, DESKEYLEN);
-					break;
-				}
+				passtokey(&k, in);
+				memmove(safe->machkey, k.des, DESKEYLEN);
+				memmove(safe->aesmachkey, k.aes, AESKEYLEN);
+				break;
 			}
 		}
 
-		// safe->authsum = nvcsum(safe->authkey, DESKEYLEN);
 		safe->machsum = nvcsum(safe->machkey, DESKEYLEN);
+		// safe->authsum = nvcsum(safe->authkey, DESKEYLEN);
 		safe->configsum = nvcsum(safe->config, CONFIGLEN);
 		safe->authidsum = nvcsum(safe->authid, sizeof safe->authid);
 		safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom);
+		safe->aesmachsum = nvcsum(safe->aesmachkey, AESKEYLEN);
 
 		*(Nvrsafe*)buf = *safe;
 		if(loc.fd < 0