212 lines · 4.0 KB · C
RawDownload
// 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));} voidfreepass(char *pass){	if(pass != nil){		memset(pass, 0, strlen(pass));		free(pass);	}} voidcformat(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");	}} voidcopen(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");} voidmain(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);}