devfs crypto code - alpha version

This commit is contained in:
taruti 2011-05-24 22:19:33 +00:00
parent f34231e16a
commit 9655db2550
9 changed files with 528 additions and 0 deletions

View file

@ -400,3 +400,7 @@ int okThumbprint(uchar *sha1, Thumbprint *ok);
/* 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);

View file

@ -21,6 +21,9 @@
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include "libsec.h"
int dec16(uchar *out, int lim, char *in, int n);
enum
{
@ -32,6 +35,7 @@ enum
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 @@ enum
typedef struct Inner Inner;
typedef struct Fsdev Fsdev;
typedef struct Tree Tree;
typedef struct Key Key;
struct Inner
{
@ -85,6 +90,7 @@ struct Fsdev
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 @@ struct Tree
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 @@ static char* tnames[] = {
[Fcat] "cat",
[Finter] "inter",
[Fpart] "part",
[Fcrypt] "crypt",
};
static Cmdtab configs[] = {
@ -131,6 +142,7 @@ static Cmdtab configs[] = {
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 @@ seprintdev(char *s, char *e, Fsdev *mp)
case Fmirror:
case Fcat:
case Finter:
case Fcrypt:
s = strecpy(s, e, "\n");
break;
case Fpart:
@ -434,6 +447,13 @@ setdsize(Fsdev* mp, vlong *ilen)
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 @@ parseconfig(char *a, long n, Cmdbuf **cbp, Cmdtab **ctp)
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 @@ mconfig(char* a, long n)
vlong size, start;
vlong *ilen;
char *tname, *dname, *fakef[4];
uchar key[32];
Chan **idev;
Cmdbuf *cb;
Cmdtab *ct;
@ -575,6 +600,10 @@ mconfig(char* a, long n)
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 @@ Fail:
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 @@ Fail:
}
setdsize(mp, ilen);
poperror();
wunlock(&lck);
free(idev);
@ -970,6 +1010,63 @@ io(Fsdev *mp, Inner *in, int isread, void *a, long l, vlong off)
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 @@ mread(Chan *c, void *a, long n, vlong off)
"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();
@ -1235,6 +1335,9 @@ mwrite(Chan *c, void *a, long n, vlong off)
(up && up->errstr? up->errstr: ""));
break;
case Fcrypt:
res = cryptio(mp, Iswrite, a, n, off);
break;
}
Done:
poperror();

View file

@ -0,0 +1,14 @@
// 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;

View file

@ -0,0 +1,173 @@
// 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);
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);
}

View file

@ -0,0 +1,10 @@
</$objtype/mkfile
BIN=/$objtype/bin
TARG=cryptsetup
OFILES=\
cryptsetup.$O\
readcons.$O\
pbkdf2.$O\
</sys/src/cmd/mkone

View file

@ -0,0 +1,77 @@
/* $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;
}

View file

@ -0,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];
}
}
}

View file

@ -0,0 +1,69 @@
// Author Taru Karttunen <taruti@taruti.net>
// 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;
}

View file

@ -17,6 +17,7 @@ CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\
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}