Run a revision on the GBDE encryption facility.

Replace ARC4 with SHA2-512.
Change lock-structure encoding to use random ordering rather for obscurity.
Encrypt lock-structure with AES/256 instead of AES/128.
Change kkey derivation to be MD5 hash based.
Watch for malloc(M_NOWAIT) failures and ditch our cache when they happen.
Remove clause 3 of the license with NAI Labs consent.

Many thanks to "Lucky Green" <shamrock@cypherpunks.to> and "David
Wagner" <daw@cs.berkeley.edu>, for code reading, inputs and
suggestions.

This code has still not been stared at for 10 years by a gang of
hard-core cryptographers.  Discretion advised.

NB: These changes result in the on-disk format changing: dump/restore needed.

Sponsored by:   DARPA & NAI Labs.
This commit is contained in:
Poul-Henning Kamp 2002-11-04 09:27:01 +00:00
parent 0bd7c043ab
commit 5afa461402
9 changed files with 621 additions and 366 deletions

View File

@ -5,11 +5,14 @@ SRCS= gbde.c template.c
SRCS+= geom_enc.c
SRCS+= rijndael-alg-fst.c
SRCS+= rijndael-api-fst.c
SRCS+= sha2.c
SRCS+= g_bde_lock.c
CFLAGS+= -I${.CURDIR}/../../sys
.PATH: ${.CURDIR}/../../sys/geom ${.CURDIR}/../../sys/geom/bde \
${.CURDIR}/../../sys/crypto/rijndael
.PATH: ${.CURDIR}/../../sys/geom \
${.CURDIR}/../../sys/geom/bde \
${.CURDIR}/../../sys/crypto/rijndael \
${.CURDIR}/../../sys/crypto/sha2
CLEANFILES+= template.c

View File

@ -16,9 +16,6 @@
.\" 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
@ -69,9 +66,21 @@
.Ar destination
.Op Fl n Ar key
.Op Fl l Ar lockfile
.Op Fl p Ar pass-phrase
.Op Fl L Ar lockfile
.Sh NOTICE
.Pp
Please be aware that this code has not yet received much review
and analysis by qualified cryptographers and therefore should be considered
a slightly suspect experimental facility.
.Pp
We cannot at this point guarantee that the on-disk format will not change
in response to reviews or bug-fixes, so potential users are adviced to
be prepared that
.Xr dump 8 /
.Xr restore 8
based migrations may be called for in the future.
.Sh DESCRIPTION
The
.Nm
program is the only official operation and management interface for the
.Xr gbde 4
@ -128,15 +137,27 @@ argument
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.
Be aware that using this option may exposed the pass-phrase to other
users who happen to run
.Xr
ps 1
or similar while the command is running.
.Pp
The
.Fl P Ar new-pass-phrase
argument
can be used to specify the new pass-phrase to the
.Cm init
and
.Cm setkey
subcommand.
subcommands.
If not specified, the user is prompted for the new pass-phrase on the
controlling terminal.
Be aware that using this option may exposed the pass-phrase to other
users who happen to run
.Xr
ps 1
or similar while the command is running.
.Sh EXAMPLES
To initialize a device, using default parameters:
.Dl # gbde init /dev/ad0s1f -l /etc/ad0s1f.lock
@ -168,3 +189,6 @@ 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
.Sh BUGS
The cryptographic algorithms and the over-all design has not been
attacked mercilessly for over 10 years by a gang or cryptoanalysts.

View File

@ -16,9 +16,6 @@
* 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
@ -51,13 +48,50 @@
#include <libutil.h>
#include <sys/errno.h>
#include <sys/disk.h>
#include <sys/stat.h>
#include <crypto/rijndael/rijndael.h>
#include <crypto/sha2/sha2.h>
#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0)
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
extern const char template[];
#if 0
static void
g_hexdump(void *ptr, int length)
{
int i, j, k;
unsigned char *cp;
cp = ptr;
for (i = 0; i < length; i+= 16) {
printf("%04x ", i);
for (j = 0; j < 16; j++) {
k = i + j;
if (k < length)
printf(" %02x", cp[k]);
else
printf(" ");
}
printf(" |");
for (j = 0; j < 16; j++) {
k = i + j;
if (k >= length)
printf(" ");
else if (cp[k] >= ' ' && cp[k] <= '~')
printf("%c", cp[k]);
else
printf(".");
}
printf("|\n");
}
}
#endif
static void __dead2
usage(const char *reason)
{
@ -114,14 +148,13 @@ random_bits(void *p, u_int len)
}
/* XXX: not nice */
static u_char sbox[256];
static u_char sha2[SHA512_DIGEST_LENGTH];
static void
reset_passphrase(struct g_bde_softc *sc)
{
memcpy(sc->arc4_sbox, sbox, 256);
sc->arc4_i = sc->arc4_j = 0;
memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH);
}
static void
@ -130,8 +163,8 @@ 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);
g_bde_hash_pass(sc, input, strlen(input));
memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH);
return;
}
for (;;) {
@ -160,12 +193,12 @@ setup_passphrase(struct g_bde_softc *sc, int sure, const char *input)
}
break;
}
g_bde_arc4_seed(sc, buf1, strlen(buf1));
memcpy(sbox, sc->arc4_sbox, 256);
g_bde_hash_pass(sc, buf1, strlen(buf1));
memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH);
}
static void
encrypt_sector(void *d, int len, void *key)
encrypt_sector(void *d, int len, int klen, void *key)
{
keyInstance ki;
cipherInstance ci;
@ -174,7 +207,7 @@ encrypt_sector(void *d, int len, void *key)
error = rijndael_cipherInit(&ci, MODE_CBC, NULL);
if (error <= 0)
errx(1, "rijndael_cipherInit=%d", error);
error = rijndael_makeKey(&ki, DIR_ENCRYPT, 128, key);
error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key);
if (error <= 0)
errx(1, "rijndael_makeKeY=%d", error);
error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d);
@ -205,12 +238,12 @@ cmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile)
ffd = open(lfile, O_RDONLY, 0);
if (ffd < 0)
err(1, lfile);
read(ffd, buf + 256, 16);
read(ffd, buf + sizeof(sc->sha2), 16);
close(ffd);
} else {
memset(buf + 256, 0, 16);
memset(buf + sizeof(sc->sha2), 0, 16);
}
memcpy(buf, sc->arc4_sbox, 256);
memcpy(buf, sc->sha2, sizeof(sc->sha2));
i = ioctl(gfd, GEOMCONFIGGEOM, &gcg);
if (i != 0)
@ -241,12 +274,28 @@ cmd_detach(const char *dest)
}
static void
cmd_open(struct g_bde_softc *sc, int dfd __unused, const char *l_opt, u_int *nkey)
cmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey)
{
int error;
int ffd;
u_char keyloc[16];
u_int sectorsize;
off_t mediasize;
struct stat st;
error = ioctl(dfd, DIOCGSECTORSIZE, &sectorsize);
if (error)
sectorsize = 512;
error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize);
if (error) {
error = fstat(dfd, &st);
if (error == 0 && S_ISREG(st.st_mode))
mediasize = st.st_size;
else
error = ENOENT;
}
if (error)
mediasize = (off_t)-1;
if (l_opt != NULL) {
ffd = open(l_opt, O_RDONLY, 0);
if (ffd < 0)
@ -257,8 +306,8 @@ cmd_open(struct g_bde_softc *sc, int dfd __unused, const char *l_opt, u_int *nke
memset(keyloc, 0, sizeof keyloc);
}
error = g_bde_decrypt_lock(sc, sbox, keyloc, 0xffffffff,
512, nkey);
error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize,
sectorsize, nkey);
if (error == ENOENT)
errx(1, "Lock was destroyed.");
if (error == ESRCH)
@ -294,12 +343,10 @@ cmd_nuke(struct g_bde_key *gl, int dfd , int 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);
@ -352,32 +399,16 @@ cmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const
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);
i = g_bde_encode_lock(sc, gl, q);
if (i < 0)
errx(1, "programming error encoding lock");
/*
* 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);
encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16);
offset = gl->lsector[key] & ~(gl->sectorsize - 1);
offset2 = lseek(dfd, offset, SEEK_SET);
if (offset2 != offset)

View File

@ -16,9 +16,6 @@
.\" 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
@ -42,6 +39,18 @@
.Nd Geom Based Disk Encryption.
.Sh SYNOPSIS
.Cd options GEOM_BDE
.Sh NOTICE
.Pp
Please be aware that this code has not yet received much review
and analysis by qualified cryptographers and therefore should be considered
a slightly suspect experimental facility.
.Pp
We cannot at this point guarantee that the on-disk format will not change
in response to reviews or bug-fixes, so potential users are adviced to
be prepared that
.Xr dump 8 /
.Xr restore 8
based migrations may be called for in the future.
.Sh DESCRIPTION
.Pp
The objective of this facility is to provide a high degree of
@ -64,64 +73,78 @@ a valid pass-phrase.
Four cryptographic barriers must be passed to gain access to the data,
and only a valid pass-phrase will allow yield this access.
.Pp
When the pass-phrase is entered, it is used to seed an ARC4 based
byte oriented PNRG which is used to produce what we call the
When the pass-phrase is entered, it is hashed with SHA2 into a 512 bit
.Dq key-material .
This is a way to producing cryptographic usable keys from a typically
all-ASCII pass-phrase of an unpredictable user-selected length.
.Ss First barrier: the location of the \&"master-lock" sector.
.Ss First barrier: the location of the \&"lock-sector".
During initialization, up to four indepenent but mutually aware
.Dq master-key
.Dq lock-sectors
sectors are written to the device in randomly chosen
locations.
These master-keys contain a 2048 random bit key and a number of parameters
of the layout geometry (more on this later).
Since the entire device will contain isotropic data, there is no way
short of trying, to determine which sequence of bytes contain
the encrypted master-key.
These lock-sectors contain the 2048 random bit master-key and a number
of parameters of the layout geometry (more on this later).
Since the entire device will contain isotropic data, there is no
short-cut to rapidly determine which sequence of bytes contain a lock-sector.
.Pp
To find one of these sectors, a small piece of data called the
.Dq lockdata
To locate a lock-sector, a small piece of data called the
.Dq metadata
and the key-material must be available.
The key-material decrypts the
lockdata, which contains the byte offset on the device where the
master-key is located.
If the lockdata is lost or unavailable but the key-material is at
metadata, which contains the byte offset on the device where the
corresponding lock-sector is located.
If the metadata is lost or unavailable but the key-material is at
hand, it would be feasible to do a brute force scan where each byte offset
of the device is checked to see if it contains the master-key data.
of the device is checked to see if it contains the lock-sector data.
.Ss Second barrier: decryption of the master-key using key-material.
The master-key is stored in an architecture neutral byte-sequence which
is scrambled and encrypted with the key-material.
The lock-sector contains an encrypted copy of an architecture neutral
byte-sequence which encodes the fields of the lock-structure.
The order in which these fields are encoded is determined from the key-material.
The encoded bytestream is encrypted with 256bit AES in CBC mode.
.Ss Third barrier: decryption of the sector key.
Using a PNRG like process seeded with the sector address and the 2048 bit key
from the master-key a per-sector key is derived which is used to encrypt
the sector key which is stored on the disk.
For each sector, an MD5 hash over a
.Dq salt
from the lock-sector and the sector number is used to
.Dq cherry-pick
a subset of the master key,
which hashed together with the sector offset through MD5 produces the
.Dq kkey ,
the key which encryptes the sector key.
.Ss Fourth barrier: decryption of the sector data.
The actual payload of the sector is encrypted with a single-use random bits
key.
The actual payload of the sector is encrypted with 128 bit AES in CBC mode
using a single-use random bits key.
.Ss Examining the reverse path
Assuming an attacker who knows an amount of plaintext, and has managed to
locate the corresponding encrypted sectors on the device, gaining access
to the plaintext context of other sectors is a daunting task:
.Pp
First he will have to derive from the encrypted sector and the known plain
text the sector key(s) used.
(At the time of writing, it is speculated that it could maybe be possible
to do so in only 2^80 operations which is still a staggering number).
At the time of writing, it has been speculated that it could maybe be
possible to break open AES in only 2^80 operations even so, that is still
a very impossible task.
.Pp
Armed with one or more sector keys, our patient attacker will then go
through essentially the same exercise, using the sector key and the
encrypted sector key to find the key used to encrypt the sectorkey.
.Pp
Armed with one or more of these
.Dq key-keys ,
our attacker has to derive
as much information about the 2048 bit master-key.
To do so, he
first has to reverse an MD5 hash, and then the PRNG-like algorithm
which derives the MD5 input from the master-key.
.Dq kkeys ,
our attacker has to
run them backwards through MD5.
Even though he knows that the input to MD5 was 24 bytes and has the value
of 8 of these bytes from the sector number, he is still faced with 2^128
equally likely possibilities.
.Pp
Any attacker with access to the necessary machine power will probably be
better off attempting to brute-force the pass-phrase.
Having succesfully done that, our attacker has successfully discovered
up to 16 bytes of the master-key, but is still unaware which 16 bytes,
and in which other sectors any of these known bytes contribute to the kkey.
.Pp
To unravel the last bit, the attacker has to guess the 16 byte random-bits
salt stored in the lock-sector to recover the indexes into the masterkey.
.Pp
Any attacker with access to the necessary machine power to even attempt
this attack will be better off attempting to brute-force the pass-phrase.
.Ss Postive denial facilities
Considering the infeasibility of the above attack,
gaining access to the pass-phrase will be of paramount importance for an
@ -144,13 +167,13 @@ single key, which has a complexity comparable to a number with 600 digits.
.Pp
This key exists in four copies, each of which is stored in one of
four small safes, each of which can be opened
with unique key which has a complexity comparable to a 40 digit
with unique key which has a complexity comparable to a 80 digit
number.
.Pp
In addition to the masterkey, each of the four safes also contain
the exact locations of all four key-safes which are located in
randomly chosen places on the outside surface of the vault and they
are impossible to detect when they are closed.
randomly chosen places on the outside surface of the vault where they
are practically impossible to detect when they are closed.
.Pp
Finally, each safe contains four switches which are wired to a bar
of dynamite inside each of the four safes.
@ -233,6 +256,10 @@ single-use key
.Dq ( "the skey" ) .
AES is well documented.
.Pp
No IV is used in the encryption of the sectors, the assumption being
that since the key is random bits and single-use, an IV adds nothing to the
security of AES.
.Pp
The random key is produced with
.Xr arc4rand 9
which is belived to do a respectable job at producing unpredictable bytes.
@ -242,35 +269,20 @@ the location of the encrypted payload data.
The stored copy is encrypted with AES in CBC mode using a 128 bit key
.Dq ( "the kkey" )
derived
from the master key using a purpose built PRNG like algorithm seeded
with the sector address of the data in question.
The function of the PRNG is to produce a hash of the masterkey
unique for each of the payload sectors on the device in one-way
sort of way.
Up to 12.5% of the masterkey (32 bytes out of 2048 bits) will be involved
in producing each kkey.
Since the one-way properties of this algorithm has not been properly
studied and therefore may have any strength, the output is subsequently
hashed using MD5 to get the final kkey.
MD5 is well documented.
from a subset of the master key chosen by the output of an MD5 hash
over a 16 byte random bit static salt and the sector offset.
Up to 6.25% of the masterkey (16 bytes out of 2048 bits) will be selected
and hashed though MD5 with the sector offset to generate the kkey.
.Pp
Up to four copies of the master-key and associated geometry information
is stored on the device in randomly chosen locations.
Each of these copies are XORed with key-material and subsequently
encrypted with AES in CBC mode using 128 bit key-material.
is stored on the device in static randomly chosen sectors.
The exact location inside the sector is randomly chosen.
The order in which the fields are encoded depends on the key-material.
The encoded byte-stream is encrypted with AES in CBC mode using 256 bit
key-material.
.Pp
The key-material is derived from the user-entered pass-phrase using
an ARC4 PRNG.
ARC4 is a very simple algorithm, the sbox of which can be in up
to 2^1700 possible states.
ARC4 is compatible with RC4, the formal documentation and analysis
of which is not publically available.
.Pp
The ARC4 PRNG is seeded with the pass-phrase as selected and entered
by the user.
Each additional byte of pass-phrase after the first 255 adds significantly
less entropy to the initial state of the ARC4 sbox due to aliasing in
the ARC4 seeding algorithm.
512 bit SHA2.
.Pp
No chain is stronger than its weakest link, which usually is poor pass-phrases.
.Sh SEE ALSO

View File

@ -16,9 +16,6 @@
* 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
@ -42,12 +39,14 @@
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/malloc.h>
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <crypto/rijndael/rijndael.h>
#include <crypto/sha2/sha2.h>
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
#define BDE_CLASS_NAME "BDE"
static void
@ -176,6 +175,7 @@ g_bde_create(struct g_createargs *ga)
g_topology_unlock();
while (sc->dead != 2 && !LIST_EMPTY(&pp->consumers))
tsleep(sc, PRIBIO, "g_bdedie", hz);
g_waitidle();
g_topology_lock();
g_destroy_provider(pp);
mtx_destroy(&sc->worklist_mutex);
@ -208,6 +208,7 @@ g_bde_create(struct g_createargs *ga)
return (error);
}
g_topology_unlock();
g_waitidle();
while (1) {
sectorsize = cp->provider->sectorsize;
mediasize = cp->provider->mediasize;
@ -217,8 +218,9 @@ g_bde_create(struct g_createargs *ga)
sc->consumer = cp;
error = g_bde_decrypt_lock(sc, ga->ptr,
(u_char *)ga->ptr + 256, mediasize, sectorsize, NULL);
bzero(sc->arc4_sbox, sizeof sc->arc4_sbox);
(u_char *)ga->ptr + (sizeof sc->sha2),
mediasize, sectorsize, NULL);
bzero(sc->sha2, sizeof sc->sha2);
if (error)
break;
kp = &sc->key;

View File

@ -16,9 +16,6 @@
* 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
@ -35,7 +32,17 @@
* $FreeBSD$
*/
/* These are quite, but not entirely unlike constants. */
#ifndef _SYS_GEOM_BDE_G_BDE_H_
#define _SYS_GEOM_BDE_G_BDE_H_ 1
/*
* These are quite, but not entirely unlike constants.
*
* They are not commented in details here, to prevent unadvisable
* experimentation. Please consult the code where they are used before you
* even think about modifying these.
*/
#define G_BDE_MKEYLEN (2048/8)
#define G_BDE_SKEYBITS 128
#define G_BDE_SKEYLEN (G_BDE_SKEYBITS/8)
@ -43,6 +50,8 @@
#define G_BDE_KKEYLEN (G_BDE_KKEYBITS/8)
#define G_BDE_MAXKEYS 4
#define G_BDE_LOCKSIZE 384
#define NLOCK_FIELDS 13
/* This just needs to be "large enough" */
#define G_BDE_KEYBYTES 304
@ -62,6 +71,7 @@ struct g_bde_sector {
u_char malloc;
enum {JUNK, IO, VALID} state;
int error;
time_t used;
};
struct g_bde_work {
@ -81,21 +91,31 @@ struct g_bde_work {
int error;
};
/*
* The decrypted contents of the lock sectors. Notice that this is not
* the same as the on-disk layout. The on-disk layout is dynamic and
* dependent on the pass-phrase.
*/
struct g_bde_key {
uint64_t sector0;
/* Physical byte offset of first byte used */
/* Physical byte offset of 1st byte used */
uint64_t sectorN;
/* Physical byte offset of first byte not used */
/* Physical byte offset of 1st byte not used */
uint64_t keyoffset;
/* Number of bytes the disk image is skewed. */
uint64_t lsector[G_BDE_MAXKEYS];
/* Physical offsets */
/* Physical byte offsets of lock sectors */
uint32_t sectorsize;
/* Our "logical" sector size */
uint32_t flags;
/* 1 = lockfile in sector 0 */
uint8_t hash[16];
uint8_t salt[16];
/* Used to frustate the kkey generation */
uint8_t spare[32];
/* For future use, random contents */
uint8_t mkey[G_BDE_MKEYLEN];
/* Our masterkey. */
/* Non-stored help-fields */
uint64_t zone_width; /* On-disk width of zone */
uint64_t zone_cont; /* Payload width of zone */
@ -114,12 +134,11 @@ struct g_bde_softc {
struct mtx worklist_mutex;
struct proc *thread;
struct g_bde_key key;
u_char arc4_sbox[256];
u_char arc4_i, arc4_j;
int dead;
u_int nwork;
u_int nsect;
u_int ncache;
u_char sha2[SHA512_DIGEST_LENGTH];
};
/* g_bde_crypt.c */
@ -133,14 +152,12 @@ int g_bde_get_key(struct g_bde_softc *sc, void *ptr, int len);
int g_bde_init_keybytes(struct g_bde_softc *sc, char *passp, int len);
/* g_bde_lock .c */
void g_bde_encode_lock(struct g_bde_key *gl, u_char *ptr);
void g_bde_decode_lock(struct g_bde_key *gl, u_char *ptr);
u_char g_bde_arc4(struct g_bde_softc *sc);
void g_bde_arc4_seq(struct g_bde_softc *sc, void *ptr, u_int len);
void g_bde_arc4_seed(struct g_bde_softc *sc, const void *ptr, u_int len);
int g_bde_keyloc_encrypt(struct g_bde_softc *sc, void *input, void *output);
int g_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, void *output);
int g_bde_decrypt_lock(struct g_bde_softc *sc, u_char *sbox, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey);
int g_bde_encode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr);
int g_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr);
int g_bde_keyloc_encrypt(struct g_bde_softc *sc, uint64_t *input, void *output);
int g_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, uint64_t *output);
int g_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey);
void g_bde_hash_pass(struct g_bde_softc *sc, const void *input, u_int len);
/* g_bde_math .c */
uint64_t g_bde_max_sector(struct g_bde_key *lp);
@ -150,3 +167,45 @@ void g_bde_map_sector(struct g_bde_key *lp, uint64_t isector, uint64_t *osector,
void g_bde_start1(struct bio *bp);
void g_bde_worker(void *arg);
/*
* These four functions wrap the raw Rijndael functions and make sure we
* explode if something fails which shouldn't.
*/
static __inline void
AES_init(cipherInstance *ci)
{
int error;
error = rijndael_cipherInit(ci, MODE_CBC, NULL);
KASSERT(error > 0, ("rijndael_cipherInit %d", error));
}
static __inline void
AES_makekey(keyInstance *ki, int dir, u_int len, void *key)
{
int error;
error = rijndael_makeKey(ki, dir, len, key);
KASSERT(error > 0, ("rijndael_makeKey %d", error));
}
static __inline void
AES_encrypt(cipherInstance *ci, keyInstance *ki, void *in, void *out, u_int len)
{
int error;
error = rijndael_blockEncrypt(ci, ki, in, len * 8, out);
KASSERT(error > 0, ("rijndael_blockEncrypt %d", error));
}
static __inline void
AES_decrypt(cipherInstance *ci, keyInstance *ki, void *in, void *out, u_int len)
{
int error;
error = rijndael_blockDecrypt(ci, ki, in, len * 8, out);
KASSERT(error > 0, ("rijndael_blockDecrypt %d", error));
}
#endif /* _SYS_GEOM_BDE_G_BDE_H_ */

View File

@ -16,9 +16,6 @@
* 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
@ -49,51 +46,12 @@
#include <sys/libkern.h>
#include <sys/md5.h>
#include <crypto/rijndael/rijndael.h>
#include <crypto/sha2/sha2.h>
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
#include <crypto/rijndael/rijndael.h>
/*
* These four functions wrap the raw Rijndael functions and make sure we
* explode if something fails which shouldn't.
*/
static void
AES_init(cipherInstance *ci)
{
int error;
error = rijndael_cipherInit(ci, MODE_CBC, NULL);
KASSERT(error > 0, ("rijndael_cipherInit %d", error));
}
static void
AES_makekey(keyInstance *ki, int dir, u_int len, void *key)
{
int error;
error = rijndael_makeKey(ki, dir, len, key);
KASSERT(error > 0, ("rijndael_makeKey %d", error));
}
static void
AES_encrypt(cipherInstance *ci, keyInstance *ki, void *in, void *out, u_int len)
{
int error;
error = rijndael_blockEncrypt(ci, ki, in, len * 8, out);
KASSERT(error > 0, ("rijndael_blockEncrypt %d", error));
}
static void
AES_decrypt(cipherInstance *ci, keyInstance *ki, void *in, void *out, u_int len)
{
int error;
error = rijndael_blockDecrypt(ci, ki, in, len * 8, out);
KASSERT(error > 0, ("rijndael_blockDecrypt %d", error));
}
/*
* Derive kkey from mkey + sector offset.
@ -120,10 +78,14 @@ g_bde_kkey(struct g_bde_softc *sc, keyInstance *ki, int dir, off_t sector)
u_int t;
MD5_CTX ct;
u_char buf[16];
u_char buf2[8];
/* We have to be architecture neutral */
g_enc_le8(buf2, sector);
MD5Init(&ct);
MD5Update(&ct, sc->key.salt, 8);
MD5Update(&ct, (void *)&sector, sizeof sector);
MD5Update(&ct, buf2, sizeof buf2);
MD5Update(&ct, sc->key.salt + 8, 8);
MD5Final(buf, &ct);
@ -131,8 +93,9 @@ g_bde_kkey(struct g_bde_softc *sc, keyInstance *ki, int dir, off_t sector)
for (t = 0; t < 16; t++) {
MD5Update(&ct, &sc->key.mkey[buf[t]], 1);
if (t == 8)
MD5Update(&ct, (void *)&sector, sizeof sector);
MD5Update(&ct, buf2, sizeof buf2);
}
bzero(buf2, sizeof buf2);
MD5Final(buf, &ct);
bzero(&ct, sizeof ct);
AES_makekey(ki, dir, G_BDE_KKEYBITS, buf);

View File

@ -16,9 +16,6 @@
* 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
@ -50,6 +47,9 @@
#include <sys/malloc.h>
#include <sys/systm.h>
#else
#include <err.h>
#define CTASSERT(foo)
#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0)
#include <errno.h>
#include <string.h>
#include <stdlib.h>
@ -57,203 +57,332 @@
#define g_free(foo) free(foo)
#endif
#include <crypto/rijndael/rijndael.h>
#include <crypto/sha2/sha2.h>
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
#include <crypto/rijndael/rijndael.h>
/*
* Hash the raw pass-phrase.
*
* Security objectives: produce from the pass-phrase a fixed length
* bytesequence with PRN like properties in a reproducible way retaining
* as much entropy from the pass-phrase as possible.
*
* SHA2-512 makes this easy.
*/
void
g_bde_hash_pass(struct g_bde_softc *sc, const void *input, u_int len)
{
SHA512_CTX cx;
SHA512_Init(&cx);
SHA512_Update(&cx, input, len);
SHA512_Final(sc->sha2, &cx);
}
/*
* Encode/Decode the lock structure in byte-sequence format.
*
* Security objectives: none.
* Security objectives: Store in pass-phrase dependent variant format.
*
* C-structure packing and byte-endianess depends on architecture, compiler
* and compiler options. We therefore explicitly encode and decode struct
* g_bde_key using an invariant byte-sequence format.
* and compiler options. Writing raw structures to disk is therefore a bad
* idea in these enlightend days.
*
* We spend a fraction of the key-material on shuffling the fields around
* so they will be stored in an unpredictable sequence.
*
* For each byte of the key-material we derive two field indexes, and swap
* the position of those two fields.
*
* I have not worked out the statistical properties of this shuffle, but
* given that the key-material has PRN properties, the primary objective
* of making it hard to figure out which bits are where in the lock sector
* is sufficiently fulfilled.
*
* We include (and shuffle) an extra hash field in the stored version for
* identification and versioning purposes. This field contains the MD5 hash
* of a version identifier (currently "0000") followed by the stored lock
* sector byte-sequence substituting zero bytes for the hash field.
*
* The stored keysequence is protected by AES/256/CBC elsewhere in the code
* so the fact that the generated byte sequence has a much higher than
* average density of zero bits (from the numeric fields) is not currently
* a concern.
*
* Should this later become a concern, a simple software update and
* pass-phrase change can remedy the situation. One possible solution
* could be to XOR the numeric fields with a key-material derived PRN.
*
* The chosen shuffle algorithm only works as long as we have no more than 16
* fields in the stored part of the lock structure (hence the CTASSERT below).
*/
void
g_bde_encode_lock(struct g_bde_key *gl, u_char *ptr)
CTASSERT(NLOCK_FIELDS <= 16);
static void
g_bde_shuffle_lock(struct g_bde_softc *sc, int *buf)
{
int i, j, k, l;
bcopy(gl->hash, ptr + 0, sizeof gl->hash);
g_enc_le8(ptr + 16, gl->sector0);
g_enc_le8(ptr + 24, gl->sectorN);
g_enc_le8(ptr + 32, gl->keyoffset);
g_enc_le4(ptr + 40, gl->sectorsize);
g_enc_le4(ptr + 44, gl->flags);
g_enc_le8(ptr + 48, gl->lsector[0]);
g_enc_le8(ptr + 56, gl->lsector[1]);
g_enc_le8(ptr + 64, gl->lsector[2]);
g_enc_le8(ptr + 72, gl->lsector[3]);
bcopy(gl->spare, ptr + 80, sizeof gl->spare);
bcopy(gl->salt, ptr + 112, sizeof gl->salt);
bcopy(gl->mkey, ptr + 128, sizeof gl->mkey);
}
/* Assign the fields sequential positions */
for(i = 0; i < NLOCK_FIELDS; i++)
buf[i] = i;
void
g_bde_decode_lock(struct g_bde_key *gl, u_char *ptr)
{
bcopy(ptr + 0, gl->hash, sizeof gl->hash);
gl->sector0 = g_dec_le8(ptr + 16);
gl->sectorN = g_dec_le8(ptr + 24);
gl->keyoffset = g_dec_le8(ptr + 32);
gl->sectorsize = g_dec_le4(ptr + 40);
gl->flags = g_dec_le4(ptr + 44);
gl->lsector[0] = g_dec_le8(ptr + 48);
gl->lsector[1] = g_dec_le8(ptr + 56);
gl->lsector[2] = g_dec_le8(ptr + 64);
gl->lsector[3] = g_dec_le8(ptr + 72);
bcopy(ptr + 80, gl->spare, sizeof gl->spare);
bcopy(ptr + 112, gl->salt, sizeof gl->salt);
bcopy(ptr + 128, gl->mkey, sizeof gl->mkey);
}
/*
* Generate key-material used for protecting lock sectors.
*
* Security objectives: from the pass-phrase provide by the user, produce a
* reproducible stream of bits/bytes which resemeble pseudo-random bits.
*
* This is the stream-cipher algorithm called ARC4. See for instance the
* description in "Applied Cryptography" by Bruce Scneier.
*/
u_char
g_bde_arc4(struct g_bde_softc *sc)
{
u_char c;
sc->arc4_j += sc->arc4_sbox[++sc->arc4_i];
c = sc->arc4_sbox[sc->arc4_i];
sc->arc4_sbox[sc->arc4_i] = sc->arc4_sbox[sc->arc4_j];
sc->arc4_sbox[sc->arc4_j] = c;
c = sc->arc4_sbox[sc->arc4_i] + sc->arc4_sbox[sc->arc4_j];
c = sc->arc4_sbox[c];
return (c);
}
void
g_bde_arc4_seq(struct g_bde_softc *sc, void *ptr, u_int len)
{
u_char *p;
p = ptr;
while (len--)
*p++ = g_bde_arc4(sc);
}
void
g_bde_arc4_seed(struct g_bde_softc *sc, const void *ptr, u_int len)
{
u_char k[256], c;
const u_char *p;
u_int i;
p = ptr;
sc->arc4_i = 0;
bzero(k, sizeof k);
while(len--)
k[sc->arc4_i++] ^= *p++;
sc->arc4_j = 0;
for (i = 0; i < 256; i++)
sc->arc4_sbox[i] = i;
for (i = 0; i < 256; i++) {
sc->arc4_j += sc->arc4_sbox[i] + k[i];
c = sc->arc4_sbox[i];
sc->arc4_sbox[i] = sc->arc4_sbox[sc->arc4_j];
sc->arc4_sbox[sc->arc4_j] = c;
/* Then mix it all up */
for(i = 48; i < sizeof(sc->sha2); i++) {
j = sc->sha2[i] % NLOCK_FIELDS;
k = (sc->sha2[i] / NLOCK_FIELDS) % NLOCK_FIELDS;
l = buf[j];
buf[j] = buf[k];
buf[k] = l;
}
sc->arc4_i = 0;
sc->arc4_j = 0;
}
int
g_bde_encode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
{
int shuffle[NLOCK_FIELDS];
u_char *hash, *p;
int i;
MD5_CTX c;
p = ptr;
hash = NULL;
g_bde_shuffle_lock(sc, shuffle);
for (i = 0; i < NLOCK_FIELDS; i++) {
switch(shuffle[i]) {
case 0:
g_enc_le8(p, gl->sector0);
p += 8;
break;
case 1:
g_enc_le8(p, gl->sectorN);
p += 8;
break;
case 2:
g_enc_le8(p, gl->keyoffset);
p += 8;
break;
case 3:
g_enc_le4(p, gl->sectorsize);
p += 4;
break;
case 4:
g_enc_le4(p, gl->flags);
p += 4;
break;
case 5:
case 6:
case 7:
case 8:
g_enc_le8(p, gl->lsector[shuffle[i] - 5]);
p += 8;
break;
case 9:
bcopy(gl->spare, p, sizeof gl->spare);
p += sizeof gl->spare;
break;
case 10:
bcopy(gl->salt, p, sizeof gl->salt);
p += sizeof gl->salt;
break;
case 11:
bcopy(gl->mkey, p, sizeof gl->mkey);
p += sizeof gl->mkey;
break;
case 12:
bzero(p, 16);
hash = p;
p += 16;
break;
}
}
if(ptr + G_BDE_LOCKSIZE != p)
return(-1);
if (hash == NULL)
return(-1);
MD5Init(&c);
MD5Update(&c, "0000", 4); /* Versioning */
MD5Update(&c, ptr, G_BDE_LOCKSIZE);
MD5Final(hash, &c);
return(0);
}
int
g_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
{
int shuffle[NLOCK_FIELDS];
u_char *p;
u_char hash[16], hash2[16];
MD5_CTX c;
int i;
p = ptr;
g_bde_shuffle_lock(sc, shuffle);
for (i = 0; i < NLOCK_FIELDS; i++) {
switch(shuffle[i]) {
case 0:
gl->sector0 = g_dec_le8(p);
p += 8;
break;
case 1:
gl->sectorN = g_dec_le8(p);
p += 8;
break;
case 2:
gl->keyoffset = g_dec_le8(p);
p += 8;
break;
case 3:
gl->sectorsize = g_dec_le4(p);
p += 4;
break;
case 4:
gl->flags = g_dec_le4(p);
p += 4;
break;
case 5:
case 6:
case 7:
case 8:
gl->lsector[shuffle[i] - 5] = g_dec_le8(p);
p += 8;
break;
case 9:
bcopy(p, gl->spare, sizeof gl->spare);
p += sizeof gl->spare;
break;
case 10:
bcopy(p, gl->salt, sizeof gl->salt);
p += sizeof gl->salt;
break;
case 11:
bcopy(p, gl->mkey, sizeof gl->mkey);
p += sizeof gl->mkey;
break;
case 12:
bcopy(p, hash2, sizeof hash2);
bzero(p, sizeof hash2);
p += sizeof hash2;
break;
}
}
if(ptr + G_BDE_LOCKSIZE != p)
return(-1);
MD5Init(&c);
MD5Update(&c, "0000", 4); /* Versioning */
MD5Update(&c, ptr, G_BDE_LOCKSIZE);
MD5Final(hash, &c);
if (bcmp(hash, hash2, sizeof hash2))
return (1);
return (0);
}
/*
* Encrypt/Decrypt the metadata address with key-material.
* Encode/Decode the locksector address ("metadata") with key-material.
*
* Security objectives: Encode/Decode the metadata encrypted by key-material.
*
* A simple AES/128/CBC will do. We take care to always store the metadata
* in the same endianess to make it MI.
*
* In the typical case the metadata is stored in encrypted format in sector
* zero on the media, but at the users discretion or if the piece of the
* device used (sector0...sectorN) does not contain sector zero, it can
* be stored in a filesystem or on a PostIt.
*
* The inability to easily locate the lock sectors makes an attack on a
* cold disk much less attractive, without unduly inconveniencing the
* legitimate user who can feasibly do a brute-force scan if the metadata
* was lost.
*/
int
g_bde_keyloc_encrypt(struct g_bde_softc *sc, void *input, void *output)
g_bde_keyloc_encrypt(struct g_bde_softc *sc, uint64_t *input, void *output)
{
u_char *p;
u_char buf[16], buf1[16];
u_int i;
u_char buf[16];
keyInstance ki;
cipherInstance ci;
bcopy(input, output, 16);
return 0;
rijndael_cipherInit(&ci, MODE_CBC, NULL);
p = input;
g_bde_arc4_seq(sc, buf, sizeof buf);
for (i = 0; i < sizeof buf; i++)
buf1[i] = p[i] ^ buf[i];
g_bde_arc4_seq(sc, buf, sizeof buf);
rijndael_makeKey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, buf);
rijndael_blockEncrypt(&ci, &ki, buf1, 16 * 8, output);
g_enc_le8(buf, input[0]);
g_enc_le8(buf + 8, input[1]);
AES_init(&ci);
AES_makekey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, sc->sha2 + 0);
AES_encrypt(&ci, &ki, buf, output, sizeof buf);
bzero(buf, sizeof buf);
bzero(&ci, sizeof ci);
bzero(&ki, sizeof ki);
return (0);
}
int
g_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, void *output)
g_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, uint64_t *output)
{
u_char *p;
u_char buf1[16], buf2[16];
u_int i;
keyInstance ki;
cipherInstance ci;
u_char buf[16];
bcopy(input, output, 16);
return 0;
rijndael_cipherInit(&ci, MODE_CBC, NULL);
g_bde_arc4_seq(sc, buf1, sizeof buf1);
g_bde_arc4_seq(sc, buf2, sizeof buf2);
rijndael_makeKey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, buf2);
rijndael_blockDecrypt(&ci, &ki, input, 16 * 8, output);
p = output;
for (i = 0; i < sizeof buf1; i++)
p[i] ^= buf1[i];
AES_init(&ci);
AES_makekey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, sc->sha2 + 0);
AES_decrypt(&ci, &ki, input, buf, sizeof buf);
output[0] = g_dec_le8(buf);
output[1] = g_dec_le8(buf + 8);
bzero(buf, sizeof buf);
bzero(&ci, sizeof ci);
bzero(&ki, sizeof ki);
return (0);
}
/*
* Encode/Decode lock sectors, do the real work.
* Find and Encode/Decode lock sectors.
*
* Security objective: given the pass-phrase, find, decrypt, decode and
* validate the lock sector contents.
*
* For ondisk metadata we cannot know beforehand which of the lock sectors
* a given pass-phrase opens so we must try each of the metadata copies in
* sector zero in turn. If metadata was passed as an argument, we don't
* have this problem.
*
*/
static int
g_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *sbox, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
g_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
{
u_char *buf, k1buf[16], k2buf[G_BDE_LOCKSIZE], k3buf[16], *q;
u_char *buf, *q;
struct g_bde_key *gl;
uint64_t off[2];
int error, m, i;
MD5_CTX c;
keyInstance ki;
cipherInstance ci;
rijndael_cipherInit(&ci, MODE_CBC, NULL);
bcopy(sbox, sc->arc4_sbox, 256);
sc->arc4_i = 0;
sc->arc4_j = 0;
gl = &sc->key;
/* Try to decrypt the metadata */
error = g_bde_keyloc_decrypt(sc, meta, off);
if (error)
return(error);
/* loose the random part */
off[1] = 0;
/* If it points ito thin blue air, forget it */
if (off[0] + G_BDE_LOCKSIZE > (uint64_t)mediasize) {
bzero(off, sizeof off);
off[0] = 0;
return (EINVAL);
}
off[1] = 0;
/* The lock data may span two physical sectors. */
m = 1;
if (off[0] % sectorsize > sectorsize - G_BDE_LOCKSIZE)
m++;
/* Read the suspected sector(s) */
buf = g_read_data(sc->consumer,
off[0] - (off[0] % sectorsize),
m * sectorsize, &error);
@ -262,92 +391,83 @@ g_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *sbox, u_char *meta, off_t me
return(error);
}
/* Find the byte-offset of the stored byte sequence */
q = buf + off[0] % sectorsize;
off[1] = 0;
/* If it is all zero, somebody nuked our lock sector */
for (i = 0; i < G_BDE_LOCKSIZE; i++)
off[1] += q[i];
if (off[1] == 0) {
off[0] = 0;
g_free(buf);
return (ESRCH);
}
g_bde_arc4_seq(sc, k1buf, sizeof k1buf);
g_bde_arc4_seq(sc, k2buf, sizeof k2buf);
g_bde_arc4_seq(sc, k3buf, sizeof k3buf);
MD5Init(&c);
MD5Update(&c, "0000", 4); /* XXX: for future versioning */
MD5Update(&c, k1buf, 16);
MD5Final(k1buf, &c);
rijndael_makeKey(&ki, DIR_DECRYPT, 128, k3buf);
bzero(k3buf, sizeof k3buf);
rijndael_blockDecrypt(&ci, &ki, q, G_BDE_LOCKSIZE * 8, q);
for (i = 0; i < G_BDE_LOCKSIZE; i++)
q[i] ^= k2buf[i];
bzero(k2buf, sizeof k2buf);
if (bcmp(q, k1buf, sizeof k1buf)) {
bzero(k1buf, sizeof k1buf);
bzero(buf, sectorsize * m);
g_free(buf);
/* Decrypt the byte-sequence in place */
AES_init(&ci);
AES_makekey(&ki, DIR_DECRYPT, 256, sc->sha2 + 16);
AES_decrypt(&ci, &ki, q, q, G_BDE_LOCKSIZE);
/* Decode the byte-sequence */
i = g_bde_decode_lock(sc, gl, q);
q = NULL;
if (i < 0) {
off[0] = 0;
return (ENOTDIR);
return (EDOOFUS); /* Programming error */
} else if (i > 0) {
off[0] = 0;
return (ENOTDIR); /* Hash didn't match */
}
bzero(k1buf, sizeof k1buf);
g_bde_decode_lock(gl, q);
bzero(buf, sectorsize * m);
g_free(buf);
/* If the masterkey is all zeros, user destroyed it */
off[1] = 0;
for (i = 0; i < (int)sizeof(gl->mkey); i++)
off[1] += gl->mkey[i];
if (off[1] == 0) {
off[0] = 0;
if (off[1] == 0)
return (ENOENT);
}
/* Finally, find out which key was used by matching the byte offset */
for (i = 0; i < G_BDE_MAXKEYS; i++)
if (nkey != NULL && off[0] == gl->lsector[i])
*nkey = i;
off[0] = 0;
return (0);
}
/*
* Encode/Decode lock sectors.
*/
int
g_bde_decrypt_lock(struct g_bde_softc *sc, u_char *sbox, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
g_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
{
u_char *buf, buf1[16];
int error, e, i;
/* set up the key-material */
bcopy(keymat, sc->sha2, SHA512_DIGEST_LENGTH);
/* If passed-in metadata is non-zero, use it */
bzero(buf1, sizeof buf1);
if (bcmp(buf1, meta, sizeof buf1))
return (g_bde_decrypt_lockx(sc, sbox, meta, mediasize,
return (g_bde_decrypt_lockx(sc, meta, mediasize,
sectorsize, nkey));
/* Read sector zero */
buf = g_read_data(sc->consumer, 0, sectorsize, &error);
if (buf == NULL)
return(error);
error = 0;
/* Try each index in turn, save indicative errors for final result */
error = EINVAL;
for (i = 0; i < G_BDE_MAXKEYS; i++) {
e = g_bde_decrypt_lockx(sc, sbox, buf + i * 16, mediasize,
e = g_bde_decrypt_lockx(sc, buf + i * 16, mediasize,
sectorsize, nkey);
/* Success or destroyed master key terminates */
if (e == 0 || e == ENOENT) {
error = e;
break;
}
if (e == ESRCH)
error = ENOTDIR;
else if (e != 0)
if (e != 0 && error == EINVAL)
error = e;
}
g_free(buf);

View File

@ -16,9 +16,6 @@
* 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
@ -70,9 +67,12 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <crypto/rijndael/rijndael.h>
#include <crypto/sha2/sha2.h>
#include <geom/geom.h>
#include <geom/bde/g_bde.h>
@ -81,6 +81,7 @@ static struct g_bde_sector * g_bde_new_sector(struct g_bde_work *wp, u_int len);
static void g_bde_release_sector(struct g_bde_work *wp, struct g_bde_sector *sp);
static struct g_bde_sector *g_bde_get_sector(struct g_bde_work *wp, off_t offset);
static int g_bde_start_read(struct g_bde_sector *sp);
static void g_bde_purge_sector(struct g_bde_softc *sc, int fraction);
/*
* Work item allocation.
@ -181,6 +182,20 @@ g_bde_new_sector(struct g_bde_work *wp, u_int len)
static u_int g_bde_ncache;
SYSCTL_UINT(_debug, OID_AUTO, gbde_ncache, CTLFLAG_RD, &g_bde_ncache, 0, "");
static void
g_bde_purge_one_sector(struct g_bde_softc *sc, struct g_bde_sector *sp)
{
g_trace(G_T_TOPOLOGY, "g_bde_purge_one_sector(%p, %p)", sc, sp);
if (sp->ref != 0)
return;
TAILQ_REMOVE(&sc->freelist, sp, list);
g_bde_ncache--;
sc->ncache--;
bzero(sp->data, sp->size);
g_bde_delete_sector(sc, sp);
}
static struct g_bde_sector *
g_bde_get_sector(struct g_bde_work *wp, off_t offset)
{
@ -189,6 +204,14 @@ g_bde_get_sector(struct g_bde_work *wp, off_t offset)
g_trace(G_T_TOPOLOGY, "g_bde_get_sector(%p, %jd)", wp, (intmax_t)offset);
sc = wp->softc;
if (malloc_last_fail() < g_bde_ncache)
g_bde_purge_sector(sc, -1);
sp = TAILQ_FIRST(&sc->freelist);
if (sp != NULL && sp->ref == 0 && sp->used + 300 < time_uptime)
g_bde_purge_one_sector(sc, sp);
TAILQ_FOREACH(sp, &sc->freelist, list) {
if (sp->offset == offset)
break;
@ -200,7 +223,12 @@ g_bde_get_sector(struct g_bde_work *wp, off_t offset)
if (sp->ref == 1)
sp->owner = wp;
} else {
if (!TAILQ_EMPTY(&sc->freelist))
if (malloc_last_fail() < g_bde_ncache) {
TAILQ_FOREACH(sp, &sc->freelist, list)
if (sp->ref == 0)
break;
}
if (sp == NULL && !TAILQ_EMPTY(&sc->freelist))
sp = TAILQ_FIRST(&sc->freelist);
if (sp != NULL && sp->ref > 0)
sp = NULL;
@ -227,6 +255,12 @@ g_bde_get_sector(struct g_bde_work *wp, off_t offset)
TAILQ_INSERT_TAIL(&sc->freelist, sp, list);
}
wp->ksp = sp;
if (sp == NULL) {
g_bde_purge_sector(sc, -1);
sp = g_bde_get_sector(wp, offset);
}
if (sp != NULL)
sp->used = time_uptime;
KASSERT(sp != NULL, ("get_sector failed"));
return(sp);
}
@ -273,7 +307,14 @@ g_bde_purge_sector(struct g_bde_softc *sc, int fraction)
int n;
g_trace(G_T_TOPOLOGY, "g_bde_purge_sector(%p)", sc);
n = sc->ncache / fraction + 1;
if (fraction > 0)
n = sc->ncache / fraction + 1;
else
n = g_bde_ncache - malloc_last_fail();
if (n < 0)
return;
if (n > sc->ncache)
n = sc->ncache;
while(n--) {
TAILQ_FOREACH(sp, &sc->freelist, list) {
if (sp->ref != 0)