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:
parent
0bd7c043ab
commit
5afa461402
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
111
sbin/gbde/gbde.c
111
sbin/gbde/gbde.c
@ -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, §orsize);
|
||||
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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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 *)§or, 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 *)§or, 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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user