shithub: riscv

Download patch

ref: 9655db255097b84cf742b7a33c74432d4eb3425a
parent: f34231e16a9780a1aa1b9fe5dad1776dd82caa44
author: taruti <[email protected]>
date: Tue May 24 18:19:33 EDT 2011

devfs crypto code - alpha version

--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -400,3 +400,7 @@
 /* readcert.c */
 uchar	*readcert(char *filename, int *pcertlen);
 PEMChain*readcertchain(char *filename);
+
+/* aes_xts.c */
+int aes_xts_encrypt(ulong tweak[], ulong ecb[],  vlong sectorNumber, uchar *input, uchar *output, ulong len) ;
+int aes_xts_decrypt(ulong tweak[], ulong ecb[], vlong sectorNumber, uchar *input, uchar *output, ulong len);
\ No newline at end of file
--- a/sys/src/9/port/devfs.c
+++ b/sys/src/9/port/devfs.c
@@ -21,7 +21,10 @@
 #include "io.h"
 #include "ureg.h"
 #include "../port/error.h"
+#include "libsec.h"
 
+int  dec16(uchar *out, int lim, char *in, int n);
+
 enum
 {
 	Fnone,
@@ -32,6 +35,7 @@
 	Fclear,			/* start over */
 	Fdel,			/* delete a configure device */
 	Fdisk,			/* set default tree and sector sz*/
+	Fcrypt,			/* encrypted device */
 
 	Sectorsz = 1,
 	Blksize	= 8*1024,	/* for Finter only */
@@ -65,6 +69,7 @@
 typedef struct Inner Inner;
 typedef struct Fsdev Fsdev;
 typedef struct Tree Tree;
+typedef struct Key Key;
 
 struct Inner
 {
@@ -85,6 +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 */
 };
 
 struct Tree
@@ -95,6 +101,10 @@
 	uint	nadevs;		/* number of allocated devices in devs */
 };
 
+struct Key {
+	AESstate tweak, ecb;
+};
+
 #define dprint if(debug)print
 
 extern Dev fsdevtab;		/* forward */
@@ -121,6 +131,7 @@
 	[Fcat]		"cat",
 	[Finter]	"inter",
 	[Fpart]		"part",
+	[Fcrypt]	"crypt",
 };
 
 static Cmdtab configs[] = {
@@ -131,6 +142,7 @@
 	Fclear,	"clear",	1,
 	Fdel,	"del",		2,
 	Fdisk,	"disk",		0,
+	Fcrypt,	"crypt",	0,
 };
 
 static char Egone[] = "device is gone";		/* file has been removed */
@@ -156,6 +168,7 @@
 	case Fmirror:
 	case Fcat:
 	case Finter:
+	case Fcrypt:
 		s = strecpy(s, e, "\n");
 		break;
 	case Fpart:
@@ -434,6 +447,13 @@
 				mp->size = inlen - mp->start;
 			}
 			break;
+		case Fcrypt:
+			if(inlen > (64*1024)) {
+				mp->size = inlen - (64 * 1024);
+			} else {
+				mp->size = 0;
+			}
+			break;
 		}
 	}
 	if(mp->type == Finter)
@@ -478,6 +498,10 @@
 		if(cb->nf != 4 && (cb->nf != 3 || source == nil))
 			error("ctl usage: part new [file] off len");
 		break;
+	case Fcrypt:
+		if(cb->nf != 3)
+			error("ctl usage: crypt newname device keyhex");
+		break;
 	}
 }
 
@@ -529,6 +553,7 @@
 	vlong	size, start;
 	vlong	*ilen;
 	char	*tname, *dname, *fakef[4];
+	uchar key[32];
 	Chan	**idev;
 	Cmdbuf	*cb;
 	Cmdtab	*ct;
@@ -575,6 +600,10 @@
 		free(cb);
 		mdelctl("*", "*");		/* del everything */
 		return;
+	case Fcrypt:
+		dec16(key, 32, cb->f[2], 64);
+		cb->nf -= 1;
+		break;
 	case Fpart:
 		if(cb->nf == 3){
 			/*
@@ -662,6 +691,15 @@
 		mp->start = start * sectorsz;
 		mp->size = size * sectorsz;
 	}
+	if(mp->type == Fcrypt) {
+		Key *k = mallocz(sizeof(Key), 1);
+		if(k == nil)
+			error(Enomem);
+		setupAESstate(&k->tweak, &key[0], 16, nil);
+		setupAESstate(&k->ecb, &key[16], 16, nil);
+		memset(key, 0, 32);
+		mp->extra = k;
+	}
 	for(i = 1; i < cb->nf; i++){
 		inprv = mp->inner[i-1] = mallocz(sizeof(Inner), 1);
 		if(inprv == nil)
@@ -673,6 +711,8 @@
 	}
 	setdsize(mp, ilen);
 
+
+
 	poperror();
 	wunlock(&lck);
 	free(idev);
@@ -970,6 +1010,63 @@
 	return wl;
 }
 
+static long
+cryptio(Fsdev *mp, int isread, uchar *a, long l, vlong off)
+{
+	long wl, ws, wo;
+	uchar *buf;
+	Chan	*mc;
+	Inner *in;
+	Key *k;
+
+	in = mp->inner[0];
+	// Header
+	off += 64*1024;
+
+	mc = in->idev;
+	if(mc == nil)
+		error(Egone);
+	if (waserror()) {
+		print("#k: %s: byte %,lld count %ld (of #k/%s): %s error: %s\n",
+			in->iname, off, l, mp->name, (isread? "read": "write"),
+			(up && up->errstr? up->errstr: ""));
+		nexterror();
+	}
+	
+	if(off % 512 != 0 || l%512 !=0)
+		error(Eio);
+	
+	wo = (l > 16384) ? 16384 : l;
+	buf = mallocz(wo, 1);
+	if(!buf)
+		error(Enomem);
+	k = (Key*)(mp->extra);
+
+	for(ws = 0; ws < l; ws+=wo) {
+		if (isread) {
+			wl = devtab[mc->type]->read(mc, buf, wo, off);
+			if(wl!=wo)
+				error(Eio);
+			for(wl=0; wl<wo; wl+=512) {
+				aes_xts_decrypt(k->tweak.ekey, k->ecb.dkey, off, buf+wl, a+ws+wl, 512);
+				off += 512;
+			}
+		} else {
+			for(wl=0; wl<wo; wl+=512) {
+				aes_xts_encrypt(k->tweak.ekey, k->ecb.ekey, off, a+ws+wl, buf+wl, 512);
+				off += 512;
+			}
+
+			wl = devtab[mc->type]->write(mc, buf, wo, off-wo);
+			if(wl!=wo)
+				error(Eio);
+		}
+	}
+	free(buf);
+	poperror();
+	return ws;
+}
+
 /* NB: a transfer could span multiple inner devices */
 static long
 catio(Fsdev *mp, int isread, void *a, long n, vlong off)
@@ -1140,6 +1237,9 @@
 				"from mirror: %s\n", mp->name, off, n,
 				(up && up->errstr? up->errstr: ""));
 		break;
+	case Fcrypt:
+		res = cryptio(mp, Isread, a, n, off);
+		break;
 	}
 Done:
 	poperror();
@@ -1234,6 +1334,9 @@
 				"to mirror: %s\n", mp->name, off, n,
 				(up && up->errstr? up->errstr: ""));
 
+		break;
+	case Fcrypt:
+		res = cryptio(mp, Iswrite, a, n, off);
 		break;
 	}
 Done:
--- /dev/null
+++ b/sys/src/cmd/cryptsetup/crypt.h
@@ -1,0 +1,14 @@
+// Author Taru Karttunen <[email protected]>
+// 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;
--- /dev/null
+++ b/sys/src/cmd/cryptsetup/cryptsetup.c
@@ -1,0 +1,173 @@
+// Author Taru Karttunen <[email protected]>
+// 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);
+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 deviceorfile \t\t\t\t\t# Format file or device\ncryptsetup -o deviceorfile >> /dev/fs/ctl \t# Open file or device\n");
+	exits("usage");
+}
+
+enum
+{
+	NoMode,
+	Format,
+	Open,
+};
+
+
+void
+main(int argc, char *argv[])
+{
+	int mode;
+	char *file;
+
+	mode = 0;
+
+	ARGBEGIN {
+	default:
+		usage();
+	case 'f':
+		mode = Format;
+		break;
+	case 'o':
+		mode = Open;
+		break;
+	} ARGEND;
+
+	if((mode == NoMode) || (argc != 1))
+		usage();
+
+	file = argv[0];
+
+	switch(mode) {
+	case Format:
+		format(file);
+		break;
+	case Open:
+		copen(file);
+		break;
+	}
+}
+
+void
+format(char *file)
+{
+	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(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(file, 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 written\n");
+}
+
+void copen(char *file) {
+	unsigned char pass[32], buf[1024*64], tkey[16], tivec[16];
+	XtsState s;
+	int i,j,fd;
+	AESstate cbc;
+	char *base, fdpath[1024];
+
+
+	if((fd = open(file, OREAD)) < 0)
+		exits("Cannot open disk");
+	
+	if(read(fd, buf, 1024*64) != 1024*64) 
+		exits("Cannot read disk");
+	
+	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];
+		}
+
+
+
+	openpass:
+		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);
+
+		aes_decrypt(cbc.dkey, cbc.rounds, &buf[(64*1024)-16], &buf[(64*1024)-16]);
+
+		/* make the pad for checking crypto */
+		for(i=0; i<8; i++)
+			if((buf[(64*1024)-8+i] ^ buf[(64*1024)-16+i]) != 255) {
+				goto openpass;
+			}
+
+	base = utfrrune(file, '/');
+	fd2path(fd, fdpath, 1024);
+	j = sprint((char*)buf, "crypt %s %s ", base ? base+1 : file, fdpath);
+	
+	for(i=0; i<32; i++) {
+		sprint((char*)&buf[j], "%02X", s.Master[i]);
+		j += 2; 
+	}
+	sprint((char*)&buf[j], "\n");
+	print("%s\n", (char*)buf);
+}
\ No newline at end of file
--- /dev/null
+++ b/sys/src/cmd/cryptsetup/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=cryptsetup
+OFILES=\
+	cryptsetup.$O\
+	readcons.$O\
+	pbkdf2.$O\
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/sys/src/cmd/cryptsetup/pbkdf2.c
@@ -1,0 +1,77 @@
+/*	$OpenBSD: pbkdf2.c,v 1.1 2008/06/14 06:28:27 djm Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Damien Bergamini <[email protected]>
+ *
+ * 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;
+}
--- /dev/null
+++ b/sys/src/cmd/cryptsetup/readcons.c
@@ -1,0 +1,77 @@
+/* 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/libsec/port/aes_xts.c
@@ -1,0 +1,69 @@
+// Author Taru Karttunen <[email protected]>
+// This file can be used as both Public Domain or Creative Commons CC0.
+#include <u.h>
+#include <libsec.h>
+
+#define AesBlockSize 16
+
+static void xor128(uchar* o,uchar* i1,uchar* i2) {
+	((ulong*)o)[0] = ((ulong*)i1)[0] ^ ((ulong*)i2)[0];
+	((ulong*)o)[1] = ((ulong*)i1)[1] ^ ((ulong*)i2)[1];
+	((ulong*)o)[2] = ((ulong*)i1)[2] ^ ((ulong*)i2)[2];
+	((ulong*)o)[3] = ((ulong*)i1)[3] ^ ((ulong*)i2)[3];
+}
+
+static void gf_mulx(uchar* x) {
+    ulong t = ((((ulong*)(x))[3] & 0x80000000u) ? 0x00000087u : 0);;
+    ((ulong*)(x))[3] = (((ulong*)(x))[3] << 1) | (((ulong*)(x))[2] & 0x80000000u ? 1 : 0);
+    ((ulong*)(x))[2] = (((ulong*)(x))[2] << 1) | (((ulong*)(x))[1] & 0x80000000u ? 1 : 0);
+    ((ulong*)(x))[1] = (((ulong*)(x))[1] << 1) | (((ulong*)(x))[0] & 0x80000000u ? 1 : 0);
+    ((ulong*)(x))[0] = (((ulong*)(x))[0] << 1) ^ t;
+
+}
+
+int aes_xts_encrypt(ulong tweak[], ulong ecb[],  vlong sectorNumber, uchar *input, uchar *output, ulong len) {
+	uchar T[16], x[16];
+	int i;
+	
+	if(len % 16 != 0)
+		return -1;
+
+	for(i=0; i<AesBlockSize; i++) {
+		T[i] = (uchar)(sectorNumber & 0xFF);
+		sectorNumber = sectorNumber >> 8;
+	}
+	
+	aes_encrypt(tweak, 10, T, T);
+
+	for (i=0; i<len; i+=AesBlockSize) {
+		xor128(&x[0], &input[i], &T[0]);
+		aes_encrypt(ecb, 10, x, x);
+		xor128(&output[i], &x[0], &T[0]);
+		gf_mulx(&T[0]);
+	}
+	return 0;
+}
+
+int aes_xts_decrypt(ulong tweak[], ulong ecb[], vlong sectorNumber, uchar *input, uchar *output, ulong len) {
+	uchar T[16], x[16];
+	int i;
+	
+	if(len % 16 != 0)
+		return -1;
+
+	for(i=0; i<AesBlockSize; i++) {
+		T[i] = (uchar)(sectorNumber & 0xFF);
+		sectorNumber = sectorNumber >> 8;
+	}
+	
+	aes_encrypt(tweak, 10, T, T);
+
+	for (i=0; i<len; i+=AesBlockSize) {
+		xor128(&x[0], &input[i], &T[0]);
+		aes_decrypt(ecb, 10, x, x);
+		xor128(&output[i], &x[0], &T[0]);
+		gf_mulx(&T[0]);
+	}
+	return 0;
+}
+
--- a/sys/src/libsec/port/mkfile
+++ b/sys/src/libsec/port/mkfile
@@ -17,6 +17,7 @@
 	egsign.c egverify.c \
 	dsagen.c dsaalloc.c dsaprivtopub.c dsasign.c dsaverify.c \
 	tlshand.c thumb.c readcert.c \
+	aes_xts.c  \
 
 ALLOFILES=${CFILES:%.c=%.$O}