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
This commit is contained in:
parent
f3feafc476
commit
234137bce3
10 changed files with 226 additions and 384 deletions
|
@ -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 @@ is the last path element of the
|
|||
.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)
|
||||
|
|
|
@ -11,9 +11,9 @@ $objtype
|
|||
cat
|
||||
cfs
|
||||
chmod
|
||||
cryptsetup
|
||||
dd
|
||||
disk
|
||||
cryptsetup
|
||||
edisk
|
||||
fdisk
|
||||
prep
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
BIN=/$objtype/bin
|
||||
TARG=cryptsetup
|
||||
OFILES=\
|
||||
cryptsetup.$O\
|
||||
readcons.$O\
|
||||
pbkdf2.$O\
|
||||
|
||||
</sys/src/cmd/mkone
|
|
@ -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;
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
212
sys/src/cmd/disk/cryptsetup.c
Normal file
212
sys/src/cmd/disk/cryptsetup.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -6,6 +6,7 @@ TARG=exsort\
|
|||
mkext\
|
||||
mkfs\
|
||||
partfs\
|
||||
cryptsetup\
|
||||
|
||||
DIRS=\
|
||||
9660\
|
||||
|
|
Loading…
Reference in a new issue