shithub: riscv

Download patch

ref: 234137bce39a03eab02044234c8f970498ccc5b0
parent: f3feafc476ff108231dd6e0e3ac3cd420a62a81c
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Oct 24 16:56:11 EDT 2016

fix bugs and cleanup cryptsetup code

devfs:

- fix memory leak in devfs leaking the aes key
- allocate aes-xts cipher state in secure memory
- actually check if the hexkey got fully parsed

cryptsetup:

- get rid of stupid "type YES" prompt
- use genrandom() to generate salts and keys
- rewrite cryptsetup to use common pbkdf2 and readcons routines
- fix alot of error handling and simplify the code
- move cryptsetup command to disk/cryptsetup
- update cryptsetup(8) manual page

diff: cannot open a/sys/src/cmd/cryptsetup//null: file does not exist: 'a/sys/src/cmd/cryptsetup//null'
--- a/sys/man/8/cryptsetup
+++ b/sys/man/8/cryptsetup
@@ -2,15 +2,15 @@
 .SH NAME
 cryptsetup \- setup encrypted partition
 .SH SYNOPSIS
-.B cryptsetup
+.B disk/cryptsetup
 .B -f
 .I files ...
 .br
-.B cryptsetup
+.B disk/cryptsetup
 .B -o
 .I files ...
 .br
-.B cryptsetup
+.B disk/cryptsetup
 .B -i
 .I files ...
 .SH DESCRIPTION
@@ -49,7 +49,7 @@
 .I files
 argument.
 .SH SOURCE
-.B /sys/src/cmd/cryptsetup
+.B /sys/src/cmd/disk/cryptsetup.c
 .SH SEE ALSO
 .IR aes (2) ,
 .IR fs (3)
--- a/sys/src/9/boot/bootfs.proto
+++ b/sys/src/9/boot/bootfs.proto
@@ -11,9 +11,9 @@
 		cat
 		cfs
 		chmod
-		cryptsetup
 		dd
 		disk
+			cryptsetup
 			edisk
 			fdisk
 			prep
--- a/sys/src/9/port/devfs.c
+++ b/sys/src/9/port/devfs.c
@@ -90,7 +90,7 @@
 	vlong	start;		/* start address (for Fpart) */
 	uint	ndevs;		/* number of inner devices */
 	Inner	*inner[Ndevs];	/* inner devices */
-	void *extra;                /* extra state for the device */
+	Key	*key;		/* crypt key */
 };
 
 struct Tree
@@ -351,6 +351,7 @@
 		}
 	wunlock(&lck);
 
+	secfree(mp->key);
 	free(mp->name);
 	for(i = 0; i < mp->ndevs; i++){
 		in = mp->inner[i];
@@ -359,8 +360,6 @@
 		free(in->iname);
 		free(in);
 	}
-	if(debug)
-		memset(mp, 9, sizeof *mp);	/* poison */
 	free(mp);
 }
 
@@ -553,7 +552,7 @@
 	vlong	size, start;
 	vlong	*ilen;
 	char	*tname, *dname, *fakef[4];
-	uchar key[32];
+	uchar	key[32];
 	Chan	**idev;
 	Cmdbuf	*cb;
 	Cmdtab	*ct;
@@ -601,7 +600,8 @@
 		mdelctl("*", "*");		/* del everything */
 		return;
 	case Fcrypt:
-		dec16(key, 32, cb->f[2], 64);
+		if(dec16(key, 32, cb->f[2], strlen(cb->f[2])) != 32)
+			error("bad hexkey");
 		cb->nf -= 1;
 		break;
 	case Fpart:
@@ -693,13 +693,11 @@
 		mp->size = size * sectorsz;
 	}
 	if(mp->type == Fcrypt) {
-		Key *k = mallocz(sizeof(Key), 1);
-		if(k == nil)
-			error(Enomem);
+		Key *k = secalloc(sizeof(Key));
 		setupAESstate(&k->tweak, &key[0], 16, nil);
 		setupAESstate(&k->ecb, &key[16], 16, nil);
 		memset(key, 0, 32);
-		mp->extra = k;
+		mp->key = k;
 	}
 	for(i = 1; i < cb->nf; i++){
 		inprv = mp->inner[i-1] = mallocz(sizeof(Inner), 1);
@@ -712,8 +710,6 @@
 	}
 	setdsize(mp, ilen);
 
-
-
 	poperror();
 	wunlock(&lck);
 	free(idev);
@@ -1033,7 +1029,7 @@
 	if(off < 0 || l <= 0 || ((off|l) & (Sectsz-1)))
 		error(Ebadarg);
 
-	k = mp->extra;
+	k = mp->key;
 	in = mp->inner[0];
 	mc = in->idev;
 	if(mc == nil)
--- a/sys/src/cmd/cryptsetup/crypt.h
+++ /dev/null
@@ -1,14 +1,0 @@
-// Author Taru Karttunen <taruti@taruti.net>
-// This file can be used as both Public Domain or Creative Commons CC0.
-#include <libsec.h>
-
-typedef struct {
-	unsigned char Salt[16];
-	unsigned char Key[32];
-} Slot;
-
-typedef struct {
-	unsigned char Master[32];
-	Slot Slots[8];
-	AESstate C1, C2;
-} XtsState;
--- a/sys/src/cmd/cryptsetup/cryptsetup.c
+++ /dev/null
@@ -1,189 +1,0 @@
-// Author Taru Karttunen <taruti@taruti.net>
-// This file can be used as both Public Domain or Creative Commons CC0.
-#include		<u.h>
-#include		<libc.h>
-#include		"crypt.h"
-
-void format(char *file[]);
-void copen(char *file[], int);
-char*readcons(char *prompt, char *def, int raw, char *buf, int nbuf);
-int pkcs5_pbkdf2(const unsigned char *pass, int pass_len, const unsigned char *salt, int salt_len, unsigned char *key, int key_len, int rounds);
-
-void 
-usage(void)
-{
-	print("usage: \ncryptsetup -f files \t\t# Format file or device\ncryptsetup -o files \t\t# Print commandline for open\ncryptsetup -i files\t\t# Install (open) files\n");
-	exits("usage");
-}
-
-enum
-{
-	NoMode,
-	Format,
-	Open,
-	Install,
-};
-
-
-void
-main(int argc, char *argv[])
-{
-	int mode;
-
-	mode = 0;
-
-	ARGBEGIN {
-	default:
-		usage();
-	case 'f':
-		mode = Format;
-		break;
-	case 'o':
-		mode = Open;
-		break;
-	case 'i':
-		mode = Install;
-		break;
-	} ARGEND;
-
-	if((mode == NoMode) || (argc < 1))
-		usage();
-
-	switch(mode) {
-	case Format:
-		format(argv);
-		break;
-	case Install:
-	case Open:
-		copen(argv, mode);
-		break;
-	}
-}
-
-void
-format(char *files[])
-{
-	char trand[48], pass1[64], pass2[64];
-	unsigned char tkey[16], tivec[16], buf[64*1024];
-	XtsState s;
-	AESstate cbc;
-	int i,j, fd;
-
-	do {
-		readcons("password", nil, 1, pass1, 64);
-		readcons("confirm", nil, 1, pass2, 64);
-	} while(strcmp(pass1, pass2) != 0);
-
-	do {
-		readcons("Are you sure you want to delete all data? (YES to procees)", nil, 0, (char*)buf, 4);
-	} while(strcmp((char*)buf, "YES") != 0);
-
-	srand(truerand());
-
-	for(;*files;files++) {
-
-		for(i = 0; i < 16*4096; i++)
-			buf[i] = rand();
-	
-		for(i = 0; i < 48; i+=4)
-			*((unsigned*)&trand[i]) = truerand();
-		memcpy(s.Master, trand, 32);
-		memcpy(s.Slots[0].Salt, trand+32, 16);
-
-		pkcs5_pbkdf2((unsigned char*)pass1, strlen(pass1), s.Slots[0].Salt, 16, (unsigned char*)tkey, 16, 9999);
-		memset(tivec, 0, 16);
-		setupAESstate(&cbc, tkey, 16, tivec);
-		memcpy(s.Slots[0].Key, s.Master, 32);
-		aesCBCencrypt(s.Slots[0].Key, 32, &cbc);
-
-		for(i=0; i<16; i++)
-			for(j=0; j<8; j++) {
-				buf[(4096*i)]  = 1;
-				buf[(4096*i)+(4*j)+1] = s.Slots[j].Salt[i];
-				buf[(4096*i)+(4*j)+2] = s.Slots[j].Key[i];
-				buf[(4096*i)+(4*j)+3] = s.Slots[j].Key[i+16];
-			}
-
-		if((fd = open(*files, OWRITE)) < 0)
-			exits("Cannot open disk ");
-	
-		/* make the pad for checking crypto */
-		for(i=0; i<8; i++) {
-			buf[(64*1024)-8+i] = ~buf[(64*1024)-16+i];
-		}
-		memset(tivec, 0, 16);
-		setupAESstate(&cbc, s.Master, 16, tivec);
-		aes_encrypt(cbc.ekey, cbc.rounds, &buf[(64*1024)-16], &buf[(64*1024)-16]);
-
-		write(fd, buf, 16*4096);
-
-		print("Disk %s written\n", *files);
-	}
-}
-
-void copen(char *files[], int mode) {
-	unsigned char pass[32], buf[1024*64], tkey[16], tivec[16], cbuf[16];
-	XtsState s;
-	int i,j,fd, oldpass;
-	AESstate cbc;
-	char *base, fdpath[1024];
-
-	oldpass = 0;
-	for(;*files; files++) {
-		if((fd = open(*files, OREAD)) < 0)
-			exits("Cannot open disk");
-	
-		if(read(fd, buf, 1024*64) != 1024*64) 
-			exits("Cannot read disk");
-	
-		openpass:
-			for(i=0; i<16; i++) 
-				for(j=0; j<8; j++) {
-					s.Slots[j].Salt[i] = buf[(4096*i)+(4*j)+1];
-					s.Slots[j].Key[i] = buf[(4096*i)+(4*j)+2];
-					s.Slots[j].Key[i+16] = buf[(4096*i)+(4*j)+3];
-				}
-
-			if(!oldpass)
-				readcons("Password", nil, 1, (char*)pass, 32);
-
-			memcpy(s.Master, s.Slots[0].Key, 32);
-
-			pkcs5_pbkdf2(pass, strlen((char*)pass), s.Slots[0].Salt, 16, tkey, 16, 9999);
-			memset(tivec, 0, 16);
-			setupAESstate(&cbc, tkey, 16, tivec);
-			aesCBCdecrypt(s.Master, 32, &cbc);
-		
-			memset(tivec, 0, 16);
-			setupAESstate(&cbc, s.Master, 16, tivec);
-
-			memcpy(cbuf, &buf[(64*1024)-16], 16);
-			aes_decrypt(cbc.dkey, cbc.rounds, cbuf, cbuf);
-
-			/* make the pad for checking crypto */
-			for(i=0; i<8; i++)
-				if((cbuf[i] ^ cbuf[i+8]) != 255) {
-					oldpass=0;
-					goto openpass;
-				}
-
-		base = utfrrune(*files, '/');
-		fd2path(fd, fdpath, 1024);
-		j = sprint((char*)buf, "crypt %s %s ", base ? base+1 : *files, fdpath);
-	
-		for(i=0; i<32; i++) {
-			sprint((char*)&buf[j], "%02X", s.Master[i]);
-			j += 2; 
-		}
-		buf[j++] = '\n';
-		close(fd);
-		if(mode == Install) {
-			fd = open("/dev/fs/ctl", OWRITE);
-			write(fd, buf, j);
-			close(fd);
-		} else {
-			write(1, buf, j);
-		}
-		oldpass=1;
-	}
-}
\ No newline at end of file
--- a/sys/src/cmd/cryptsetup/mkfile
+++ /dev/null
@@ -1,10 +1,0 @@
-</$objtype/mkfile
-
-BIN=/$objtype/bin
-TARG=cryptsetup
-OFILES=\
-	cryptsetup.$O\
-	readcons.$O\
-	pbkdf2.$O\
-
-</sys/src/cmd/mkone
--- a/sys/src/cmd/cryptsetup/pbkdf2.c
+++ /dev/null
@@ -1,77 +1,0 @@
-/*	$OpenBSD: pbkdf2.c,v 1.1 2008/06/14 06:28:27 djm Exp $	*/
-
-/*-
- * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <mp.h>
-#include <libsec.h>
-#define DS DigestState /* only to abbreviate SYNOPSIS */
-#define SHA1_DIGEST_LENGTH 20
-#define MIN(a,b) ((a < b) ? a : b)
-
-/*
- * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
- * Code based on IEEE Std 802.11-2007, Annex H.4.2.
- */
-int
-pkcs5_pbkdf2(const unsigned char *pass, int pass_len, const unsigned char *salt, int salt_len,
-    unsigned char *key, int key_len, int rounds)
-{
-	unsigned char *asalt, obuf[SHA1_DIGEST_LENGTH];
-	unsigned char d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH];
-	unsigned i, j;
-	unsigned count;
-	unsigned r;
-
-	if (rounds < 1 || key_len == 0)
-		return -1;
-	if (salt_len == 0)
-		return -1;
-	if ((asalt = malloc(salt_len + 4)) == nil)
-		return -1;
-
-	memcpy(asalt, salt, salt_len);
-
-	for (count = 1; key_len > 0; count++) {
-		asalt[salt_len + 0] = (count >> 24) & 0xff;
-		asalt[salt_len + 1] = (count >> 16) & 0xff;
-		asalt[salt_len + 2] = (count >> 8) & 0xff;
-		asalt[salt_len + 3] = count & 0xff;
-		hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1, nil);
-		memcpy(obuf, d1, sizeof(obuf));
-
-		for (i = 1; i < rounds; i++) {
-			hmac_sha1(d1, sizeof(d1), pass, pass_len, d2, nil);
-			memcpy(d1, d2, sizeof(d1));
-			for (j = 0; j < sizeof(obuf); j++)
-				obuf[j] ^= d1[j];
-		}
-
-		r = MIN(key_len, SHA1_DIGEST_LENGTH);
-		memcpy(key, obuf, r);
-		key += r;
-		key_len -= r;
-	};
-	memset(asalt, 0, salt_len + 4);
-	free(asalt);
-	memset(d1, 0, sizeof(d1));
-	memset(d2, 0, sizeof(d2));
-	memset(obuf, 0, sizeof(obuf));
-
-	return 0;
-}
--- a/sys/src/cmd/cryptsetup/readcons.c
+++ /dev/null
@@ -1,77 +1,0 @@
-/* From /sys/src/libauthsrv/readnvram.c, LPL licensed */
-#include <u.h>
-#include <libc.h>
-
-
-char*
-readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
-{
-	int fdin, fdout, ctl, n, m;
-	char line[10];
-
-	fdin = open("/dev/cons", OREAD);
-	if(fdin < 0)
-		fdin = 0;
-	fdout = open("/dev/cons", OWRITE);
-	if(fdout < 0)
-		fdout = 1;
-	if(def != nil)
-		fprint(fdout, "%s[%s]: ", prompt, def);
-	else
-		fprint(fdout, "%s: ", prompt);
-	if(raw){
-		ctl = open("/dev/consctl", OWRITE);
-		if(ctl >= 0)
-			write(ctl, "rawon", 5);
-	} else
-		ctl = -1;
-
-	m = 0;
-	for(;;){
-		n = read(fdin, line, 1);
-		if(n == 0){
-			close(ctl);
-			werrstr("readcons: EOF");
-			return nil;
-		}
-		if(n < 0){
-			close(ctl);
-			werrstr("can't read cons");
-			return nil;
-		}
-		if(line[0] == 0x7f)
-			exits(0);
-		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
-			if(raw){
-				write(ctl, "rawoff", 6);
-				write(fdout, "\n", 1);
-				close(ctl);
-			}
-			buf[m] = '\0';
-			if(buf[0]=='\0' && def)
-				strcpy(buf, def);
-			return buf;
-		}
-		if(line[0] == '\b'){
-			if(m > 0)
-				m--;
-		}else if(line[0] == 0x15){	/* ^U: line kill */
-			m = 0;
-			if(def != nil)
-				fprint(fdout, "%s[%s]: ", prompt, def);
-			else
-				fprint(fdout, "%s: ", prompt);
-		}else{
-			if(m >= nbuf-1){
-				fprint(fdout, "line too long\n");
-				m = 0;
-				if(def != nil)
-					fprint(fdout, "%s[%s]: ", prompt, def);
-				else
-					fprint(fdout, "%s: ", prompt);
-			}else
-				buf[m++] = line[0];
-		}
-	}
-}
-
--- /dev/null
+++ b/sys/src/cmd/disk/cryptsetup.c
@@ -1,0 +1,212 @@
+// Original Author Taru Karttunen <taruti@taruti.net>
+// This file can be used as both Public Domain or Creative Commons CC0.
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+#include <authsrv.h>
+
+typedef struct {
+	uchar Salt[16];
+	uchar Key[32];
+} Slot;
+
+typedef struct {
+	uchar Master[32];
+	Slot Slots[8];
+	AESstate C1, C2;
+} XtsState;
+
+uchar zeros[16] = {0};
+uchar buf[64*1024];
+AESstate cbc;
+XtsState s;
+
+void 
+setupkey(char *pass, uchar salt[16], AESstate *aes)
+{
+	uchar tkey[32];
+
+	pbkdf2_x((uchar*)pass, strlen(pass), salt, 16, 9999, tkey, 32, hmac_sha1, SHA1dlen);
+	setupAESstate(aes, tkey, 16, zeros);
+	memset(tkey, 0, sizeof(tkey));
+}
+
+void
+freepass(char *pass)
+{
+	if(pass != nil){
+		memset(pass, 0, strlen(pass));
+		free(pass);
+	}
+}
+
+void
+cformat(char *files[])
+{
+	char *pass, *tmp;
+	int fd, i, j;
+
+	pass = nil;
+	do {
+		freepass(pass);
+		pass = readcons("Password", nil, 1);
+		if(pass == nil || pass[0] == 0)
+			sysfatal("input aborted");
+		tmp = readcons("Confirm", nil, 1);
+		if(tmp == nil || tmp[0] == 0)
+			sysfatal("input aborted");
+		i = strcmp(pass, tmp);
+		freepass(tmp);
+	} while(i != 0);
+
+	for(;*files != nil; files++) {
+		genrandom((uchar*)&s, sizeof(s));
+		setupkey(pass, s.Slots[0].Salt, &cbc);
+		memcpy(s.Slots[0].Key, s.Master, 32);
+		aesCBCencrypt(s.Slots[0].Key, 32, &cbc);
+
+		genrandom(buf, 16*4096);
+		for(i=0; i<16; i++)
+			for(j=0; j<8; j++) {
+				buf[(4096*i)+(4*j)+1] = s.Slots[j].Salt[i];
+				buf[(4096*i)+(4*j)+2] = s.Slots[j].Key[i];
+				buf[(4096*i)+(4*j)+3] = s.Slots[j].Key[i+16];
+			}
+
+		if((fd = open(*files, OWRITE)) < 0)
+			sysfatal("open disk: %r");
+	
+		/* make the pad for checking crypto */
+		for(i=0; i<8; i++)
+			buf[(64*1024)-8+i] = ~buf[(64*1024)-16+i];
+
+		setupAESstate(&cbc, s.Master, 16, zeros);
+		aes_encrypt(cbc.ekey, cbc.rounds, &buf[(64*1024)-16], &buf[(64*1024)-16]);
+
+		if(write(fd, buf, 64*1024) != 64*1024)
+			sysfatal("writing disk: %r");
+	}
+}
+
+void
+copen(char *files[], int ctl)
+{
+	char *pass, *name;
+	uchar cbuf[16];
+	int fd, i, j;
+
+	pass = nil;
+	for(;*files != nil; files++) {
+		memset(&s, 0, sizeof(s));
+		if((fd = open(*files, OREAD)) < 0)
+			sysfatal("open disk: %r");
+	
+		if(read(fd, buf, 1024*64) != 1024*64) 
+			sysfatal("read disk: %r");
+	
+	retrypass:
+		for(i=0; i<16; i++)
+			for(j=0; j<8; j++) {
+				s.Slots[j].Salt[i] = buf[(4096*i)+(4*j)+1];
+				s.Slots[j].Key[i] = buf[(4096*i)+(4*j)+2];
+				s.Slots[j].Key[i+16] = buf[(4096*i)+(4*j)+3];
+			}
+
+		if(pass == nil){
+			pass = readcons("Password", nil, 1);
+			if(pass == nil || pass[0] == 0)
+				sysfatal("input aborted");
+		}
+
+		setupkey(pass, s.Slots[0].Salt, &cbc);
+		memcpy(s.Master, s.Slots[0].Key, 32);
+		aesCBCdecrypt(s.Master, 32, &cbc);
+		setupAESstate(&cbc, s.Master, 16, zeros);
+
+		memcpy(cbuf, &buf[(64*1024)-16], 16);
+		aes_decrypt(cbc.dkey, cbc.rounds, cbuf, cbuf);
+
+		/* make the pad for checking crypto */
+		for(i=0; i<8; i++)
+			if((cbuf[i] ^ cbuf[i+8]) != 255) {
+				freepass(pass);
+				pass = nil;
+				fprint(2, "wrong key\n");
+				goto retrypass;
+			}
+
+		fd2path(fd, (char*)buf, sizeof(buf));
+		close(fd);
+
+		if((name = strrchr(*files, '/')) != nil)
+			name++;
+		else
+			name = *files;
+
+		if(fprint(ctl, "crypt %q %q %.32H\n", name, (char*)buf, s.Master) < 0)
+			sysfatal("write: %r");
+	}
+}
+
+void 
+usage(void)
+{
+	print("usage:\n"
+		"%s -f files\t\t# Format file or device\n"
+		"%s -o files\t\t# Print commandline for open\n"
+		"%s -i files\t\t# Install (open) files\n",
+		argv0, argv0, argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+	enum {
+		NoMode,
+		Format,
+		Open,
+		Install,
+	};
+	int mode, ctl;
+
+	quotefmtinstall();
+	fmtinstall('H', encodefmt);
+
+	ctl = 1;
+	mode = NoMode;
+
+	ARGBEGIN {
+	default:
+		usage();
+	case 'f':
+		mode = Format;
+		break;
+	case 'o':
+		mode = Open;
+		break;
+	case 'i':
+		mode = Install;
+		break;
+	} ARGEND;
+
+	if(argc < 0)
+		usage();
+
+	switch(mode){
+	default:
+		usage();
+	case Format:
+		cformat(argv);
+		break;
+	case Install:
+		if((ctl = open("/dev/fs/ctl", OWRITE)) < 0)
+			sysfatal("open ctl: %r");
+		/* no break */
+	case Open:
+		copen(argv, ctl);
+		break;
+	}
+
+	exits(nil);
+}
--- a/sys/src/cmd/disk/mkfile
+++ b/sys/src/cmd/disk/mkfile
@@ -6,6 +6,7 @@
 	mkext\
 	mkfs\
 	partfs\
+	cryptsetup\
 
 DIRS=\
 	9660\