diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-10-24 20:56:11 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-10-24 20:56:11 +0200 |
commit | 234137bce39a03eab02044234c8f970498ccc5b0 (patch) | |
tree | 85e2d2707d34ac7f19ee0f7c6b23ea309701b470 /sys/src | |
parent | f3feafc476ff108231dd6e0e3ac3cd420a62a81c (diff) |
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
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/boot/bootfs.proto | 2 | ||||
-rw-r--r-- | sys/src/9/port/devfs.c | 20 | ||||
-rw-r--r-- | sys/src/cmd/cryptsetup/crypt.h | 14 | ||||
-rw-r--r-- | sys/src/cmd/cryptsetup/cryptsetup.c | 189 | ||||
-rw-r--r-- | sys/src/cmd/cryptsetup/mkfile | 10 | ||||
-rw-r--r-- | sys/src/cmd/cryptsetup/pbkdf2.c | 77 | ||||
-rw-r--r-- | sys/src/cmd/cryptsetup/readcons.c | 77 | ||||
-rw-r--r-- | sys/src/cmd/disk/cryptsetup.c | 212 | ||||
-rw-r--r-- | sys/src/cmd/disk/mkfile | 1 |
9 files changed, 222 insertions, 380 deletions
diff --git a/sys/src/9/boot/bootfs.proto b/sys/src/9/boot/bootfs.proto index 3a5b1833d..a59ad6db5 100644 --- a/sys/src/9/boot/bootfs.proto +++ b/sys/src/9/boot/bootfs.proto @@ -11,9 +11,9 @@ $objtype cat cfs chmod - cryptsetup dd disk + cryptsetup edisk fdisk prep diff --git a/sys/src/9/port/devfs.c b/sys/src/9/port/devfs.c index e5e6659b1..1dcbcf28e 100644 --- a/sys/src/9/port/devfs.c +++ b/sys/src/9/port/devfs.c @@ -90,7 +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 */ + Key *key; /* crypt key */ }; struct Tree @@ -351,6 +351,7 @@ mdeldev(Fsdev *mp) } wunlock(&lck); + secfree(mp->key); free(mp->name); for(i = 0; i < mp->ndevs; i++){ in = mp->inner[i]; @@ -359,8 +360,6 @@ mdeldev(Fsdev *mp) free(in->iname); free(in); } - if(debug) - memset(mp, 9, sizeof *mp); /* poison */ free(mp); } @@ -553,7 +552,7 @@ mconfig(char* a, long n) 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 @@ mconfig(char* a, long n) 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 @@ Fail: 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 @@ Fail: } setdsize(mp, ilen); - - poperror(); wunlock(&lck); free(idev); @@ -1033,7 +1029,7 @@ cryptio(Fsdev *mp, int isread, uchar *a, long l, vlong off) 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) diff --git a/sys/src/cmd/cryptsetup/crypt.h b/sys/src/cmd/cryptsetup/crypt.h deleted file mode 100644 index 314077a31..000000000 --- a/sys/src/cmd/cryptsetup/crypt.h +++ /dev/null @@ -1,14 +0,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; diff --git a/sys/src/cmd/cryptsetup/cryptsetup.c b/sys/src/cmd/cryptsetup/cryptsetup.c deleted file mode 100644 index 13f9a3a4b..000000000 --- a/sys/src/cmd/cryptsetup/cryptsetup.c +++ /dev/null @@ -1,189 +0,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 diff --git a/sys/src/cmd/cryptsetup/mkfile b/sys/src/cmd/cryptsetup/mkfile deleted file mode 100644 index 7dc3ede08..000000000 --- a/sys/src/cmd/cryptsetup/mkfile +++ /dev/null @@ -1,10 +0,0 @@ -</$objtype/mkfile - -BIN=/$objtype/bin -TARG=cryptsetup -OFILES=\ - cryptsetup.$O\ - readcons.$O\ - pbkdf2.$O\ - -</sys/src/cmd/mkone diff --git a/sys/src/cmd/cryptsetup/pbkdf2.c b/sys/src/cmd/cryptsetup/pbkdf2.c deleted file mode 100644 index e1b0f4e89..000000000 --- a/sys/src/cmd/cryptsetup/pbkdf2.c +++ /dev/null @@ -1,77 +0,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; -} diff --git a/sys/src/cmd/cryptsetup/readcons.c b/sys/src/cmd/cryptsetup/readcons.c deleted file mode 100644 index cc2926cf0..000000000 --- a/sys/src/cmd/cryptsetup/readcons.c +++ /dev/null @@ -1,77 +0,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]; - } - } -} - diff --git a/sys/src/cmd/disk/cryptsetup.c b/sys/src/cmd/disk/cryptsetup.c new file mode 100644 index 000000000..7e537867d --- /dev/null +++ b/sys/src/cmd/disk/cryptsetup.c @@ -0,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); +} diff --git a/sys/src/cmd/disk/mkfile b/sys/src/cmd/disk/mkfile index 20cf96a1c..e91b000d7 100644 --- a/sys/src/cmd/disk/mkfile +++ b/sys/src/cmd/disk/mkfile @@ -6,6 +6,7 @@ TARG=exsort\ mkext\ mkfs\ partfs\ + cryptsetup\ DIRS=\ 9660\ |