Complete the Geom Based Disk Encryption: Add the OAM utility.

Sponsored by:	DARPA and NAI Labs
This commit is contained in:
phk 2002-10-20 11:16:13 +00:00
parent 234874e5f3
commit c763140b9b
6 changed files with 1011 additions and 0 deletions

View File

@ -24,6 +24,7 @@ SUBDIR= adjkerntz \
fsck_msdosfs \
fsdb \
fsirand \
gbde \
growfs \
ifconfig \
init \

25
sbin/gbde/Makefile Normal file
View File

@ -0,0 +1,25 @@
# $FreeBSD$
PROG= gbde
SRCS= gbde.c template.c
SRCS+= geom_enc.c
SRCS+= rijndael-alg-fst.c
SRCS+= rijndael-api-fst.c
SRCS+= g_bde_lock.c
CFLAGS+= -I/sys
VPATH += ${.CURDIR}/../../sys/geom:${.CURDIR}/../../sys/geom/bde:${.CURDIR}/../../sys/crypto/rijndael
CLEANFILES+= template.c
MAN= gbde.8
LDADD= -lmd -lutil
.include <bsd.prog.mk>
template.c: template.txt
file2c 'const char template[] = {' ',0};' \
< ${.CURDIR}/template.txt > template.c
test: ${PROG}
sh ${.CURDIR}/test.sh

157
sbin/gbde/gbde.8 Normal file
View File

@ -0,0 +1,157 @@
.\"
.\" Copyright (c) 2002 Poul-Henning Kamp
.\" Copyright (c) 2002 Networks Associates Technology, Inc.
.\" All rights reserved.
.\"
.\" This software was developed for the FreeBSD Project by Poul-Henning Kamp
.\" and NAI Labs, the Security Research Division of Network Associates, Inc.
.\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
.\" DARPA CHATS research program.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. The names of the authors may not be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd October 19, 2002
.Os
.Dt gbde 9
.Sh NAME
.Nm gbde
.Nd Operation and management utility for Geom Based Disk Encryption.
.Sh SYNOPSIS
.Nm
attach
.Ar destination
.Op Fl l Ar lockfile
.Op Fl p Ar pass-phrase
.Nm
dettach
.Ar destination
.Nm
init
.Ar destination
.Op Fl i
.Op Fl f Ar filename
.Op Fl L Ar lockfile
.Op Fl P Ar pass-phrase
.Nm
setkey
.Ar destination
.Op Fl n Ar key
.Op Fl l Ar lockfile
.Op Fl p Ar pass-phrase
.Op Fl L Ar new-lockfile
.Op Fl P Ar new-pass-phrase
.Nm
destroy
.Ar destination
.Op Fl n Ar key
.Op Fl l Ar lockfile
.Op Fl L Ar lockfile
.Sh DESCRIPTION
The
.Nm
program is the only official operation and management interface for the
.Xr gbde 4
GEOM based disk encryption kernel facility.
The interaction between the
.Nm
program and the kernel part is not a published interface.
.Pp
The operational aspect consists of two subcommands, one to open and attach
a device and one to close and dettach
a device to the in-kernel cryptographic gbde module.
.Pp
The management part allows initialization of the master key and lock sectors
on a device, initialization and replacement of pass-phrases and
key invalidation and blackening functions.
.Pp
The
.Fl l Ar lockfile
argument is used to supply the lock selector data.
If no
.Fl l
argument is specified, the first sector is used for this purpose.
.Pp
.Fl L Ar new-lockfile
specifies the lock selector file for the key modified with the
.Ar setkey subcommand.
.Pp
The
.Fl n Ar key
argument can be used to specify which of the four keys the operation applies to.
A value of 1 to 4 selects the specified key, a value of 0 (the default) means "this key" (ie, the key used to gain access to the device) and a value of -1 means "all keys".
.Pp
The
.Fl f Ar filename
specifies an optional parameter file for use under initialization.
.Pp
Alternatively the
.Fl i
optional toggles an interactive mode where a template file with descriptions
of the parameters can be interactively edited.
.Pp
.Fl p Ar pass-phrase
specifies the pass-phrase used to opening the device.
If not specified the controlling terminal will be used to prompt the user
for the pass-phrase.
.Pp
.Fl P Ar new-pass-phrase
can be used to specify the new pass-phrase to the
.Ar setkey
subcommand.
If not specified, the user is prompted for the new pass-phrase on the
controlling terminal.
.Sh EXAMPLES
To initialize a device, using default parameters:
.Dl # gbde init /dev/ad0s1f -l /etc/ad0s1f.lock
.Pp
To attach an encrypted device:
.Dl # gbde attach ad0s1f -l /etc/ad0s1f.lock
.Pp
To dettach an encrypted device:
.Dl # gbde dettach ad0s1f
.Pp
To initialize the second key using a dettached lockfile and a trivial
pass-phrase:
.Dl # gbde setkey ad0s1f -n 2 -P foo -L key2.lockfile
.Pp
To destroy all copies of the masterkey:
.Dl # gbde destroy ad0s1f -n -1
.Sh SEE ALSO
.Xr gbde 4 ,
.Xr geom 4 .
.Rs
.%A Poul-Henning Kamp
.%T "Making sure data is lost: Spook-strength encryption of on-disk data"
.%R "Refereed paper, NORDU2003 conference"
.Re
.Sh HISTORY
This software was developed for the FreeBSD Project by Poul-Henning Kamp
and NAI Labs, the Security Research Division of Network Associates, Inc.
under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
DARPA CHATS research program.
.Sh AUTHORS
.An "Poul-Henning Kamp" Aq phk@FreeBSD.org

750
sbin/gbde/gbde.c Normal file
View File

@ -0,0 +1,750 @@
/*-
* Copyright (c) 2002 Poul-Henning Kamp
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Poul-Henning Kamp
* and NAI Labs, the Security Research Division of Network Associates, Inc.
* under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
* DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/mutex.h>
#include <md5.h>
#include <readpassphrase.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <stdlib.h>
#include <err.h>
#include <stdio.h>
#include <libutil.h>
#include <sys/errno.h>
#include <sys/disk.h>
#include <crypto/rijndael/rijndael.h>
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
extern const char template[];
static void __dead2
usage(const char *reason)
{
const char *p;
p = getprogname();
fprintf(stderr, "Usage error: %s", reason);
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t%s attach dest -l filename\n", p);
fprintf(stderr, "\t%s dettach dest\n", p);
fprintf(stderr, "\t%s init dest [-i] [-f filename] -l filename\n", p);
fprintf(stderr, "\t%s setkey dest [-n key] -l filename\n", p);
fprintf(stderr, "\t%s destroy dest [-n key] -l filename\n", p);
exit (1);
}
void *
g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
{
void *p;
int fd, i;
off_t o2;
p = malloc(length);
if (p == NULL)
err(1, "malloc");
fd = *(int *)cp;
o2 = lseek(fd, offset, SEEK_SET);
if (o2 != offset)
err(1, "lseek");
i = read(fd, p, length);
if (i != length)
err(1, "read");
if (error != NULL)
error = 0;
return (p);
}
static void
random_bits(void *p, u_int len)
{
static int fdr = -1;
int i;
if (fdr < 0) {
fdr = open("/dev/urandom", O_RDONLY);
if (fdr < 0)
err(1, "/dev/urandom");
}
i = read(fdr, p, len);
if (i != (int)len)
err(1, "read from /dev/urandom");
}
/* XXX: not nice */
static u_char sbox[256];
static void
reset_passphrase(struct g_bde_softc *sc)
{
memcpy(sc->arc4_sbox, sbox, 256);
sc->arc4_i = sc->arc4_j = 0;
}
static void
setup_passphrase(struct g_bde_softc *sc, int sure, const char *input)
{
char buf1[BUFSIZ], buf2[BUFSIZ], *p;
if (input != NULL) {
g_bde_arc4_seed(sc, input, strlen(input));
memcpy(sbox, sc->arc4_sbox, 256);
return;
}
for (;;) {
p = readpassphrase(
sure ? "Enter new passphrase:" : "Enter passphrase: ",
buf1, sizeof buf1,
RPP_ECHO_OFF | RPP_REQUIRE_TTY);
if (p == NULL)
err(1, "readpassphrase");
if (sure) {
p = readpassphrase("Reenter new passphrase: ",
buf2, sizeof buf2,
RPP_ECHO_OFF | RPP_REQUIRE_TTY);
if (p == NULL)
err(1, "readpassphrase");
if (strcmp(buf1, buf2)) {
printf("They didn't match.\n");
continue;
}
}
if (strlen(buf1) < 3) {
printf("Too short passphrase.\n");
continue;
}
break;
}
g_bde_arc4_seed(sc, buf1, strlen(buf1));
memcpy(sbox, sc->arc4_sbox, 256);
}
static void
encrypt_sector(void *d, int len, void *key)
{
keyInstance ki;
cipherInstance ci;
int error;
error = rijndael_cipherInit(&ci, MODE_CBC, NULL);
if (error <= 0)
errx(1, "rijndael_cipherInit=%d", error);
error = rijndael_makeKey(&ki, DIR_ENCRYPT, 128, key);
if (error <= 0)
errx(1, "rijndael_makeKeY=%d", error);
error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d);
if (error <= 0)
errx(1, "rijndael_blockEncrypt=%d", error);
}
static void
cmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile)
{
int gfd, i, ffd;
struct geomconfiggeom gcg;
u_char buf[256 + 16];
gfd = open("/dev/geom.ctl", O_RDWR);
if (gfd < 0)
err(1, "/dev/geom.ctl");
memset(&gcg, 0, sizeof gcg);
gcg.class.u.name = "BDE";
gcg.class.len = strlen(gcg.class.u.name);
gcg.provider.u.name = dest;
gcg.provider.len = strlen(gcg.provider.u.name);
gcg.flag = 0;
gcg.len = sizeof buf;
gcg.ptr = buf;
if (lfile != NULL) {
ffd = open(lfile, O_RDONLY, 0);
if (ffd < 0)
err(1, lfile);
read(ffd, buf + 256, 16);
close(ffd);
} else {
memset(buf + 256, 0, 16);
}
memcpy(buf, sc->arc4_sbox, 256);
i = ioctl(gfd, GEOMCONFIGGEOM, &gcg);
if (i != 0)
err(1, "ioctl(GEOMCONFIGGEOM)");
exit (0);
}
static void
cmd_dettach(const char *dest)
{
int i, gfd;
struct geomconfiggeom gcg;
gfd = open("/dev/geom.ctl", O_RDWR);
if (gfd < 0)
err(1, "/dev/geom.ctl");
memset(&gcg, 0, sizeof gcg);
gcg.class.u.name = "BDE";
gcg.class.len = strlen(gcg.class.u.name);
gcg.provider.u.name = dest;
gcg.provider.len = strlen(gcg.provider.u.name);
gcg.flag = 1;
i = ioctl(gfd, GEOMCONFIGGEOM, &gcg);
if (i != 0)
err(1, "ioctl(GEOMCONFIGGEOM)");
exit (0);
}
static void
cmd_open(struct g_bde_softc *sc, int dfd __unused, const char *l_opt, u_int *nkey)
{
int error;
int ffd;
u_char keyloc[16];
if (l_opt != NULL) {
ffd = open(l_opt, O_RDONLY, 0);
if (ffd < 0)
err(1, l_opt);
read(ffd, keyloc, sizeof keyloc);
close(ffd);
} else {
memset(keyloc, 0, sizeof keyloc);
}
error = g_bde_decrypt_lock(sc, sbox, keyloc, 0xffffffff,
512, nkey);
if (error == ENOENT)
errx(1, "Lock was destroyed.");
if (error == ESRCH)
errx(1, "Lock was nuked.");
if (error == ENOTDIR)
errx(1, "Lock not found");
if (error != 0)
errx(1, "Error %d decrypting lock", error);
if (nkey)
printf("Opened with key %u\n", *nkey);
return;
}
static void
cmd_nuke(struct g_bde_key *gl, int dfd , int key)
{
int i;
u_char *sbuf;
off_t offset, offset2;
sbuf = malloc(gl->sectorsize);
memset(sbuf, 0, gl->sectorsize);
offset = (gl->lsector[key] & ~(gl->sectorsize - 1));
offset2 = lseek(dfd, offset, SEEK_SET);
if (offset2 != offset)
err(1, "lseek");
i = write(dfd, sbuf, gl->sectorsize);
if (i != (int)gl->sectorsize)
err(1, "write");
printf("Nuked key %d\n", key);
}
static void
cmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt)
{
char buf[BUFSIZ];
int i, ffd;
uint64_t off[2];
u_char keyloc[16];
u_char *sbuf, *q;
MD5_CTX c;
off_t offset, offset2;
sbuf = malloc(gl->sectorsize);
/*
* Find the byte-offset in the lock sector where we will put the lock
* data structure. We can put it any random place as long as the
* structure fits.
*/
for(;;) {
random_bits(off, sizeof off);
off[0] &= (gl->sectorsize - 1);
if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize)
continue;
break;
}
/* Add the sector offset in bytes */
off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1));
gl->lsector[key] = off[0];
i = g_bde_keyloc_encrypt(sc, off, keyloc);
if (i)
errx(1, "g_bde_keyloc_encrypt()");
if (l_opt != NULL) {
ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (ffd < 0)
err(1, l_opt);
write(ffd, keyloc, sizeof keyloc);
close(ffd);
} else if (gl->flags & 1) {
offset2 = lseek(dfd, 0, SEEK_SET);
if (offset2 != 0)
err(1, "lseek");
i = read(dfd, sbuf, gl->sectorsize);
if (i != (int)gl->sectorsize)
err(1, "read");
memcpy(sbuf + key * 16, keyloc, sizeof keyloc);
offset2 = lseek(dfd, 0, SEEK_SET);
if (offset2 != 0)
err(1, "lseek");
i = write(dfd, sbuf, gl->sectorsize);
if (i != (int)gl->sectorsize)
err(1, "write");
} else {
errx(1, "No -L option and no space in sector 0 for lockfile");
}
/* Allocate a sectorbuffer and fill it with random junk */
if (sbuf == NULL)
err(1, "malloc");
random_bits(sbuf, gl->sectorsize);
/* Fill in the hash field with something we can recognize again */
g_bde_arc4_seq(sc, buf, 16);
MD5Init(&c);
MD5Update(&c, "0000", 4); /* XXX: for future versioning */
MD5Update(&c, buf, 16);
MD5Final(gl->hash, &c);
/* Fill random bits in the spare field */
random_bits(gl->spare, sizeof(gl->spare));
/* Encode the structure where we want it */
q = sbuf + (off[0] % gl->sectorsize);
g_bde_encode_lock(gl, q);
/*
* The encoded structure likely contains long sequences of zeros
* which stick out as a sore thumb, so we XOR with key-material
* to make it harder to recognize in a brute-force attack
*/
g_bde_arc4_seq(sc, buf, G_BDE_LOCKSIZE);
for (i = 0; i < G_BDE_LOCKSIZE; i++)
q[i] ^= buf[i];
g_bde_arc4_seq(sc, buf, 16);
encrypt_sector(q, G_BDE_LOCKSIZE, buf);
offset = gl->lsector[key] & ~(gl->sectorsize - 1);
offset2 = lseek(dfd, offset, SEEK_SET);
if (offset2 != offset)
err(1, "lseek");
i = write(dfd, sbuf, gl->sectorsize);
if (i != (int)gl->sectorsize)
err(1, "write");
printf("Wrote key %d at %jd\n", key, (intmax_t)offset);
}
static void
cmd_destroy(struct g_bde_key *gl, int nkey)
{
int i;
bzero(&gl->sector0, sizeof gl->sector0);
bzero(&gl->sectorN, sizeof gl->sectorN);
bzero(&gl->keyoffset, sizeof gl->keyoffset);
bzero(&gl->flags, sizeof gl->flags);
bzero(gl->key, sizeof gl->key);
for (i = 0; i < G_BDE_MAXKEYS; i++)
if (i != nkey)
gl->lsector[i] = ~0;
}
static void
cmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt)
{
int i;
u_char *buf;
unsigned sector_size;
uint64_t first_sector;
uint64_t last_sector;
uint64_t total_sectors;
off_t off, off2;
unsigned nkeys;
const char *p;
char *q, cbuf[BUFSIZ];
unsigned u, u2;
uint64_t o;
properties params;
bzero(gl, sizeof *gl);
if (f_opt != NULL) {
i = open(f_opt, O_RDONLY);
if (i < 0)
err(1, f_opt);
params = properties_read(i);
close (i);
} else {
/* XXX: Polish */
q = strdup("/tmp/temp.XXXXXXXXXX");
i = mkstemp(q);
if (i < 0)
err(1, q);
write(i, template, strlen(template));
close (i);
if (i_opt) {
p = getenv("EDITOR");
if (p == NULL)
p = "vi";
sprintf(cbuf, "%s %s\n", p, q);
system(cbuf);
}
i = open(q, O_RDONLY);
if (i < 0)
err(1, f_opt);
params = properties_read(i);
close (i);
unlink(q);
}
/* <sector_size> */
p = property_find(params, "sector_size");
i = ioctl(dfd, DIOCGSECTORSIZE, &u);
if (i == 0)
sector_size = u;
else if (p == NULL)
errx(1, "Missing sector_size property");
if (p != NULL) {
sector_size = strtoul(p, &q, 0);
if (!*p || *q)
errx(1, "sector_size not a proper number");
}
if (sector_size & (sector_size - 1))
errx(1, "sector_size not a power of 2");
if (sector_size < 512)
errx(1, "sector_size is smaller than 512");
buf = malloc(sector_size);
if (buf == NULL)
err(1, "Failed to malloc sector buffer");
gl->sectorsize = sector_size;
i = ioctl(dfd, DIOCGMEDIASIZE, &off);
if (i == 0) {
first_sector = 0;
total_sectors = off / sector_size;
last_sector = total_sectors - 1;
} else {
first_sector = 0;
last_sector = 0;
total_sectors = 0;
}
/* <first_sector> */
p = property_find(params, "first_sector");
if (p != NULL) {
first_sector = strtoul(p, &q, 0);
if (!*p || *q)
errx(1, "first_sector not a proper number");
}
gl->sector0 = first_sector * gl->sectorsize;
/* <last_sector> */
p = property_find(params, "last_sector");
if (p != NULL) {
last_sector = strtoul(p, &q, 0);
if (!*p || *q)
errx(1, "last_sector not a proper number");
if (last_sector <= first_sector)
errx(1, "last_sector not larger than first_sector");
total_sectors = last_sector + 1;
}
/* <total_sectors> */
p = property_find(params, "total_sectors");
if (p != NULL) {
total_sectors = strtoul(p, &q, 0);
if (!*p || *q)
errx(1, "total_sectors not a proper number");
if (last_sector == 0)
last_sector = first_sector + total_sectors - 1;
}
if (l_opt == NULL && first_sector != 0)
errx(1, "No -L new-lockfile argument and first_sector != 0");
else if (l_opt == NULL) {
first_sector++;
total_sectors--;
gl->flags |= 1;
}
if (total_sectors != (last_sector - first_sector) + 1)
errx(1, "total_sectors disagree with first_sector and last_sector");
if (total_sectors == 0)
errx(1, "missing last_sector or total_sectors");
gl->sectorN = (last_sector + 1) * gl->sectorsize;
/* Find a random keyoffset */
random_bits(&o, sizeof o);
o %= (gl->sectorN - gl->sector0);
o &= ~(gl->sectorsize - 1);
gl->keyoffset = o;
/* <number_of_keys> */
p = property_find(params, "number_of_keys");
if (p == NULL)
errx(1, "Missing number_of_keys property");
nkeys = strtoul(p, &q, 0);
if (!*p || *q)
errx(1, "number_of_keys not a proper number");
if (nkeys < 1 || nkeys > G_BDE_MAXKEYS)
errx(1, "number_of_keys out of range");
for (u = 0; u < nkeys; u++) {
for(;;) {
do {
random_bits(&o, sizeof o);
o %= gl->sectorN;
o &= ~(gl->sectorsize - 1);
} while(o < gl->sector0);
for (u2 = 0; u2 < u; u2++)
if (o == gl->lsector[u2])
break;
if (u2 < u)
continue;
break;
}
gl->lsector[u] = o;
}
for (; u < G_BDE_MAXKEYS; u++) {
do
random_bits(&o, sizeof o);
while (o < gl->sectorN);
gl->lsector[u] = o;
}
/* Flush sector zero if we use it for lockfile data */
if (gl->flags & 1) {
off2 = lseek(dfd, 0, SEEK_SET);
if (off2 != 0)
err(1, "lseek(2) to sector 0");
random_bits(buf, sector_size);
i = write(dfd, buf, sector_size);
if (i != (int)sector_size)
err(1, "write sector 0");
}
/* <random_flush> */
p = property_find(params, "random_flush");
if (p != NULL) {
off = first_sector * sector_size;
off2 = lseek(dfd, off, SEEK_SET);
if (off2 != off)
err(1, "lseek(2) to first_sector");
off2 = last_sector * sector_size;
while (off <= off2) {
random_bits(buf, sector_size);
i = write(dfd, buf, sector_size);
if (i != (int)sector_size)
err(1, "write to $device_name");
off += sector_size;
}
}
random_bits(gl->key, sizeof gl->key);
return;
}
static enum action {
ACT_HUH,
ACT_ATTACH, ACT_DETTACH,
ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE
} action;
int
main(int argc, char **argv)
{
const char *opts;
const char *l_opt, *L_opt;
const char *p_opt, *P_opt;
const char *f_opt;
const char *dest;
int i_opt, n_opt, ch, dfd, nkey, doopen;
int i;
char *q;
struct g_bde_key *gl;
struct g_bde_softc sc;
if (argc < 3)
usage("Too few arguments\n");
doopen = 0;
if (!strcmp(argv[1], "attach")) {
action = ACT_ATTACH;
opts = "l:p:";
} else if (!strcmp(argv[1], "dettach")) {
action = ACT_DETTACH;
opts = "";
} else if (!strcmp(argv[1], "init")) {
action = ACT_INIT;
doopen = 1;
opts = "f:iL:P:";
} else if (!strcmp(argv[1], "setkey")) {
action = ACT_SETKEY;
doopen = 1;
opts = "n:l:L:p:P:";
} else if (!strcmp(argv[1], "destroy")) {
action = ACT_DESTROY;
doopen = 1;
opts = "l:p:";
} else if (!strcmp(argv[1], "nuke")) {
action = ACT_NUKE;
doopen = 1;
opts = "l:p:n:";
} else {
usage("Unknown sub command\n");
}
argc--;
argv++;
dest = argv[1];
argc--;
argv++;
p_opt = NULL;
P_opt = NULL;
l_opt = NULL;
L_opt = NULL;
f_opt = NULL;
n_opt = 0;
i_opt = 0;
while((ch = getopt(argc, argv, opts)) != -1)
switch (ch) {
case 'f':
f_opt = optarg;
break;
case 'i':
i_opt = !i_opt;
case 'l':
l_opt = optarg;
break;
case 'L':
L_opt = optarg;
break;
case 'p':
p_opt = optarg;
break;
case 'P':
P_opt = optarg;
break;
case 'n':
n_opt = strtoul(optarg, &q, 0);
if (!*optarg || *q)
usage("-n argument not numeric\n");
if (n_opt < -1 || n_opt > G_BDE_MAXKEYS)
usage("-n argument out of range\n");
break;
default:
usage("Invalid option\n");
}
if (doopen) {
dfd = open(dest, O_RDWR | O_CREAT, 0644);
if (dfd < 0)
err(1, dest);
}
memset(&sc, 0, sizeof sc);
sc.consumer = (struct g_consumer *)&dfd;
gl = &sc.key;
switch(action) {
case ACT_ATTACH:
setup_passphrase(&sc, 0, p_opt);
cmd_attach(&sc, dest, l_opt);
break;
case ACT_DETTACH:
cmd_dettach(dest);
break;
case ACT_INIT:
cmd_init(gl, dfd, f_opt, i_opt, L_opt);
setup_passphrase(&sc, 1, P_opt);
cmd_write(gl, &sc, dfd, 0, L_opt);
break;
case ACT_SETKEY:
setup_passphrase(&sc, 0, p_opt);
cmd_open(&sc, dfd, l_opt, &nkey);
if (n_opt == 0)
n_opt = nkey + 1;
setup_passphrase(&sc, 1, P_opt);
cmd_write(gl, &sc, dfd, n_opt - 1, L_opt);
break;
case ACT_DESTROY:
setup_passphrase(&sc, 0, p_opt);
cmd_open(&sc, dfd, l_opt, &nkey);
cmd_destroy(gl, nkey);
reset_passphrase(&sc);
cmd_write(gl, &sc, dfd, nkey, l_opt);
break;
case ACT_NUKE:
setup_passphrase(&sc, 0, p_opt);
cmd_open(&sc, dfd, l_opt, &nkey);
if (n_opt == 0)
n_opt = nkey + 1;
if (n_opt == -1) {
for(i = 0; i < G_BDE_MAXKEYS; i++)
cmd_nuke(gl, dfd, i);
} else {
cmd_nuke(gl, dfd, n_opt - 1);
}
break;
default:
usage("Internal error\n");
}
return(0);
}

32
sbin/gbde/template.txt Normal file
View File

@ -0,0 +1,32 @@
# $FreeBSD$
#
# Sector size is the smallest unit of data which can be read or written.
# Making it too small decreases performance and decreases available space.
# Making it too large may prevent filesystems from working. 512 is the
# minimum and always safe. For UFS, use the fragment size
#
sector_size = 512
#
# Start and end of the encrypted section of the partition. Specify in
# sector numbers. If none specified, "all" will be assumed, to the
# extent the value of this can be established.
#
#first_sector = 0
#last_sector = 2879
#total_sectors = 2880
#
# An encrypted partition can have more than one key. It may be a good idea
# to make at least two keys, and save one of them for "just in case" use.
# The minimum is obviously one and the maximum is 4.
#
number_of_keys = 4
#
# Flushing the partition with random bytes prevents a brute-force attack
# from skipping sectors which obviously contains un-encrypted data.
# NB: This variable is boolean, if it is present it means "yes" even if
# you set it to the value "no"
#
#random_flush =

46
sbin/gbde/test.sh Normal file
View File

@ -0,0 +1,46 @@
#!/bin/sh
# $FreeBSD$
set -e
MD=99
mdconfig -d -u $MD || true
mdconfig -a -t malloc -s 1m -u $MD
D=/dev/md$MD
./gbde init $D -P foo -L /tmp/_l1
./gbde setkey $D -p foo -l /tmp/_l1 -P bar -L /tmp/_l1
./gbde setkey $D -p bar -l /tmp/_l1 -P foo -L /tmp/_l1
./gbde setkey $D -p foo -l /tmp/_l1 -n 2 -P foo2 -L /tmp/_l2
./gbde setkey $D -p foo2 -l /tmp/_l2 -n 3 -P foo3 -L /tmp/_l3
./gbde setkey $D -p foo3 -l /tmp/_l3 -n 4 -P foo4 -L /tmp/_l4
./gbde setkey $D -p foo4 -l /tmp/_l4 -n 1 -P foo1 -L /tmp/_l1
./gbde nuke $D -p foo1 -l /tmp/_l1 -n 4
if ./gbde nuke $D -p foo4 -l /tmp/_l4 -n 3 ; then false ; fi
./gbde destroy $D -p foo2 -l /tmp/_l2
if ./gbde destroy $D -p foo2 -l /tmp/_l2 ; then false ; fi
./gbde nuke $D -p foo1 -l /tmp/_l1 -n -1
if ./gbde nuke $D -p foo1 -l /tmp/_l1 -n -1 ; then false ; fi
if ./gbde nuke $D -p foo2 -l /tmp/_l2 -n -1 ; then false ; fi
if ./gbde nuke $D -p foo3 -l /tmp/_l3 -n -1 ; then false ; fi
if ./gbde nuke $D -p foo4 -l /tmp/_l4 -n -1 ; then false ; fi
./gbde init $D -P foo
./gbde setkey $D -p foo -P bar
./gbde setkey $D -p bar -P foo
./gbde setkey $D -p foo -n 2 -P foo2
./gbde setkey $D -p foo2 -n 3 -P foo3
./gbde setkey $D -p foo3 -n 4 -P foo4
./gbde setkey $D -p foo4 -n 1 -P foo1
mdconfig -d -u $MD || true
echo "***********"
echo "Test passed"
echo "***********"
exit 0