aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/gbde/Makefile7
-rw-r--r--sbin/gbde/gbde.834
-rw-r--r--sbin/gbde/gbde.c113
-rw-r--r--share/man/man4/gbde.4142
-rw-r--r--sys/geom/bde/g_bde.c16
-rw-r--r--sys/geom/bde/g_bde.h95
-rw-r--r--sys/geom/bde/g_bde_crypt.c57
-rw-r--r--sys/geom/bde/g_bde_lock.c454
-rw-r--r--sys/geom/bde/g_bde_work.c51
9 files changed, 612 insertions, 357 deletions
diff --git a/sbin/gbde/Makefile b/sbin/gbde/Makefile
index 87488e0cdfa7..906f1961dfb6 100644
--- a/sbin/gbde/Makefile
+++ b/sbin/gbde/Makefile
@@ -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
diff --git a/sbin/gbde/gbde.8 b/sbin/gbde/gbde.8
index 2b1ec8668b16..0ea3eeff6473 100644
--- a/sbin/gbde/gbde.8
+++ b/sbin/gbde/gbde.8
@@ -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.
diff --git a/sbin/gbde/gbde.c b/sbin/gbde/gbde.c
index 4c427a650618..a634c9c7024a 100644
--- a/sbin/gbde/gbde.c
+++ b/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, &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);
-
- /*
- * 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);
+ i = g_bde_encode_lock(sc, gl, q);
+ if (i < 0)
+ errx(1, "programming error encoding lock");
- 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)
diff --git a/share/man/man4/gbde.4 b/share/man/man4/gbde.4
index 30b76a329324..7b8b9f4d76aa 100644
--- a/share/man/man4/gbde.4
+++ b/share/man/man4/gbde.4
@@ -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.
-.Pp
-To find one of these sectors, a small piece of data called the
-.Dq lockdata
+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 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.
-.Pp
-Any attacker with access to the necessary machine power will probably be
-better off attempting to brute-force the pass-phrase.
+.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
+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
diff --git a/sys/geom/bde/g_bde.c b/sys/geom/bde/g_bde.c
index aaf6323ae5a0..234c6e6b6cb1 100644
--- a/sys/geom/bde/g_bde.c
+++ b/sys/geom/bde/g_bde.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
@@ -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;
diff --git a/sys/geom/bde/g_bde.h b/sys/geom/bde/g_bde.h
index 6354411c4119..c5f9bf5abb39 100644
--- a/sys/geom/bde/g_bde.h
+++ b/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
@@ -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_ */
diff --git a/sys/geom/bde/g_bde_crypt.c b/sys/geom/bde/g_bde_crypt.c
index 6cabb521ec49..6c545a8c3a76 100644
--- a/sys/geom/bde/g_bde_crypt.c
+++ b/sys/geom/bde/g_bde_crypt.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
@@ -49,51 +46,12 @@
#include <sys/libkern.h>
#include <sys/md5.h>
-#include <geom/geom.h>
-#include <geom/bde/g_bde.h>
-
#include <crypto/rijndael/rijndael.h>
+#include <crypto/sha2/sha2.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;
+#include <geom/geom.h>
+#include <geom/bde/g_bde.h>
- 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);
diff --git a/sys/geom/bde/g_bde_lock.c b/sys/geom/bde/g_bde_lock.c
index 29c880c102e1..d415c3068399 100644
--- a/sys/geom/bde/g_bde_lock.c
+++ b/sys/geom/bde/g_bde_lock.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
@@ -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>
-
/*
- * Encode/Decode the lock structure in byte-sequence format.
- *
- * Security objectives: none.
+ * Hash the raw pass-phrase.
*
- * 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.
+ * 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_encode_lock(struct g_bde_key *gl, u_char *ptr)
+g_bde_hash_pass(struct g_bde_softc *sc, const void *input, u_int len)
{
+ SHA512_CTX cx;
- 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);
-}
-
-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);
+ SHA512_Init(&cx);
+ SHA512_Update(&cx, input, len);
+ SHA512_Final(sc->sha2, &cx);
}
/*
- * Generate key-material used for protecting lock sectors.
+ * Encode/Decode the lock structure in byte-sequence format.
*
- * Security objectives: from the pass-phrase provide by the user, produce a
- * reproducible stream of bits/bytes which resemeble pseudo-random bits.
+ * Security objectives: Store in pass-phrase dependent variant format.
*
- * This is the stream-cipher algorithm called ARC4. See for instance the
- * description in "Applied Cryptography" by Bruce Scneier.
+ * C-structure packing and byte-endianess depends on architecture, compiler
+ * 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).
*/
-u_char
-g_bde_arc4(struct g_bde_softc *sc)
+CTASSERT(NLOCK_FIELDS <= 16);
+
+static void
+g_bde_shuffle_lock(struct g_bde_softc *sc, int *buf)
{
- 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);
+ int i, j, k, l;
+
+ /* Assign the fields sequential positions */
+ for(i = 0; i < NLOCK_FIELDS; i++)
+ buf[i] = i;
+
+ /* 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;
+ }
}
-void
-g_bde_arc4_seq(struct g_bde_softc *sc, void *ptr, u_int len)
+int
+g_bde_encode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
{
- u_char *p;
-
+ int shuffle[NLOCK_FIELDS];
+ u_char *hash, *p;
+ int i;
+ MD5_CTX c;
+
p = ptr;
- while (len--)
- *p++ = g_bde_arc4(sc);
+ 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);
}
-void
-g_bde_arc4_seed(struct g_bde_softc *sc, const void *ptr, u_int len)
+int
+g_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
{
- u_char k[256], c;
- const u_char *p;
- u_int i;
+ int shuffle[NLOCK_FIELDS];
+ u_char *p;
+ u_char hash[16], hash2[16];
+ MD5_CTX c;
+ 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;
+ 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;
+ }
}
- sc->arc4_i = 0;
- sc->arc4_j = 0;
+ 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;
-
- 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];
+ u_char buf[16];
+
+ 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);
diff --git a/sys/geom/bde/g_bde_work.c b/sys/geom/bde/g_bde_work.c
index 8b9942d28595..521177118ebb 100644
--- a/sys/geom/bde/g_bde_work.c
+++ b/sys/geom/bde/g_bde_work.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
@@ -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)