![cinap_lenrek](/assets/img/avatar_default.png)
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
213 lines
4 KiB
C
213 lines
4 KiB
C
// 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);
|
|
}
|