2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2002 Poul-Henning Kamp
5 * Copyright (c) 2002 Networks Associates Technology, Inc.
8 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
9 * and NAI Labs, the Security Research Division of Network Associates, Inc.
10 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
11 * DARPA CHATS research program.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 /* This souce file contains routines which operates on the lock sectors, both
37 * for the kernel and the userland program gbde(1).
41 #include <sys/param.h>
42 #include <sys/queue.h>
44 #include <sys/mutex.h>
45 #include <sys/endian.h>
49 #include <sys/malloc.h>
50 #include <sys/systm.h>
54 #define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0)
59 #define g_free(foo) free(foo)
62 #include <crypto/rijndael/rijndael-api-fst.h>
63 #include <crypto/sha2/sha512.h>
65 #include <geom/geom.h>
66 #include <geom/bde/g_bde.h>
69 * Hash the raw pass-phrase.
71 * Security objectives: produce from the pass-phrase a fixed length
72 * bytesequence with PRN like properties in a reproducible way retaining
73 * as much entropy from the pass-phrase as possible.
75 * SHA2-512 makes this easy.
79 g_bde_hash_pass(struct g_bde_softc *sc, const void *input, u_int len)
84 SHA512_Update(&cx, input, len);
85 SHA512_Final(sc->sha2, &cx);
89 * Encode/Decode the lock structure in byte-sequence format.
91 * Security objectives: Store in pass-phrase dependent variant format.
93 * C-structure packing and byte-endianess depends on architecture, compiler
94 * and compiler options. Writing raw structures to disk is therefore a bad
95 * idea in these enlightend days.
97 * We spend a fraction of the key-material on shuffling the fields around
98 * so they will be stored in an unpredictable sequence.
100 * For each byte of the key-material we derive two field indexes, and swap
101 * the position of those two fields.
103 * I have not worked out the statistical properties of this shuffle, but
104 * given that the key-material has PRN properties, the primary objective
105 * of making it hard to figure out which bits are where in the lock sector
106 * is sufficiently fulfilled.
108 * We include (and shuffle) an extra hash field in the stored version for
109 * identification and versioning purposes. This field contains the MD5 hash
110 * of a version identifier (currently "0000") followed by the stored lock
111 * sector byte-sequence substituting zero bytes for the hash field.
113 * The stored keysequence is protected by AES/256/CBC elsewhere in the code
114 * so the fact that the generated byte sequence has a much higher than
115 * average density of zero bits (from the numeric fields) is not currently
118 * Should this later become a concern, a simple software update and
119 * pass-phrase change can remedy the situation. One possible solution
120 * could be to XOR the numeric fields with a key-material derived PRN.
122 * The chosen shuffle algorithm only works as long as we have no more than 16
123 * fields in the stored part of the lock structure (hence the CTASSERT below).
126 CTASSERT(NLOCK_FIELDS <= 16);
129 g_bde_shuffle_lock(u_char *sha2, int *buf)
134 /* Assign the fields sequential positions */
135 for(u = 0; u < NLOCK_FIELDS; u++)
138 /* Then mix it all up */
139 for(u = 48; u < SHA512_DIGEST_LENGTH; u++) {
140 j = sha2[u] % NLOCK_FIELDS;
141 k = (sha2[u] / NLOCK_FIELDS) % NLOCK_FIELDS;
149 g_bde_encode_lock(u_char *sha2, struct g_bde_key *gl, u_char *ptr)
151 int shuffle[NLOCK_FIELDS];
158 g_bde_shuffle_lock(sha2, shuffle);
159 for (i = 0; i < NLOCK_FIELDS; i++) {
162 le64enc(p, gl->sector0);
166 le64enc(p, gl->sectorN);
170 le64enc(p, gl->keyoffset);
174 le32enc(p, gl->sectorsize);
178 le32enc(p, gl->flags);
185 le64enc(p, gl->lsector[shuffle[i] - 5]);
189 bcopy(gl->spare, p, sizeof gl->spare);
190 p += sizeof gl->spare;
193 bcopy(gl->salt, p, sizeof gl->salt);
194 p += sizeof gl->salt;
197 bcopy(gl->mkey, p, sizeof gl->mkey);
198 p += sizeof gl->mkey;
207 if(ptr + G_BDE_LOCKSIZE != p)
212 MD5Update(&c, "0000", 4); /* Versioning */
213 MD5Update(&c, ptr, G_BDE_LOCKSIZE);
219 g_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
221 int shuffle[NLOCK_FIELDS];
223 u_char hash[16], hash2[16];
228 g_bde_shuffle_lock(sc->sha2, shuffle);
229 for (i = 0; i < NLOCK_FIELDS; i++) {
232 gl->sector0 = le64dec(p);
236 gl->sectorN = le64dec(p);
240 gl->keyoffset = le64dec(p);
244 gl->sectorsize = le32dec(p);
248 gl->flags = le32dec(p);
255 gl->lsector[shuffle[i] - 5] = le64dec(p);
259 bcopy(p, gl->spare, sizeof gl->spare);
260 p += sizeof gl->spare;
263 bcopy(p, gl->salt, sizeof gl->salt);
264 p += sizeof gl->salt;
267 bcopy(p, gl->mkey, sizeof gl->mkey);
268 p += sizeof gl->mkey;
271 bcopy(p, hash2, sizeof hash2);
272 bzero(p, sizeof hash2);
277 if(ptr + G_BDE_LOCKSIZE != p)
280 MD5Update(&c, "0000", 4); /* Versioning */
281 MD5Update(&c, ptr, G_BDE_LOCKSIZE);
283 if (bcmp(hash, hash2, sizeof hash2))
289 * Encode/Decode the locksector address ("metadata") with key-material.
291 * Security objectives: Encode/Decode the metadata encrypted by key-material.
293 * A simple AES/128/CBC will do. We take care to always store the metadata
294 * in the same endianness to make it MI.
296 * In the typical case the metadata is stored in encrypted format in sector
297 * zero on the media, but at the users discretion or if the piece of the
298 * device used (sector0...sectorN) does not contain sector zero, it can
299 * be stored in a filesystem or on a PostIt.
301 * The inability to easily locate the lock sectors makes an attack on a
302 * cold disk much less attractive, without unduly inconveniencing the
303 * legitimate user who can feasibly do a brute-force scan if the metadata
308 g_bde_keyloc_encrypt(u_char *sha2, uint64_t v0, uint64_t v1, void *output)
315 le64enc(buf + 8, v1);
317 AES_makekey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, sha2 + 0);
318 AES_encrypt(&ci, &ki, buf, output, sizeof buf);
319 bzero(buf, sizeof buf);
320 bzero(&ci, sizeof ci);
321 bzero(&ki, sizeof ki);
326 g_bde_keyloc_decrypt(u_char *sha2, void *input, uint64_t *output)
333 AES_makekey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, sha2 + 0);
334 AES_decrypt(&ci, &ki, input, buf, sizeof buf);
335 *output = le64dec(buf);
336 bzero(buf, sizeof buf);
337 bzero(&ci, sizeof ci);
338 bzero(&ki, sizeof ki);
343 * Find and Encode/Decode lock sectors.
345 * Security objective: given the pass-phrase, find, decrypt, decode and
346 * validate the lock sector contents.
348 * For ondisk metadata we cannot know beforehand which of the lock sectors
349 * a given pass-phrase opens so we must try each of the metadata copies in
350 * sector zero in turn. If metadata was passed as an argument, we don't
356 g_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
359 struct g_bde_key *gl;
367 /* Try to decrypt the metadata */
368 error = g_bde_keyloc_decrypt(sc->sha2, meta, &off);
372 /* If it points into thin blue air, forget it */
373 if (off + G_BDE_LOCKSIZE > (uint64_t)mediasize) {
378 /* The lock data may span two physical sectors. */
381 if (off % sectorsize > sectorsize - G_BDE_LOCKSIZE)
384 /* Read the suspected sector(s) */
385 buf = g_read_data(sc->consumer,
386 off - (off % sectorsize),
387 m * sectorsize, &error);
393 /* Find the byte-offset of the stored byte sequence */
394 q = buf + off % sectorsize;
396 /* If it is all zero, somebody nuked our lock sector */
398 for (i = 0; i < G_BDE_LOCKSIZE; i++)
406 /* Decrypt the byte-sequence in place */
408 AES_makekey(&ki, DIR_DECRYPT, 256, sc->sha2 + 16);
409 AES_decrypt(&ci, &ki, q, q, G_BDE_LOCKSIZE);
411 /* Decode the byte-sequence */
412 i = g_bde_decode_lock(sc, gl, q);
416 return (EDOOFUS); /* Programming error */
419 return (ENOTDIR); /* Hash didn't match */
422 bzero(buf, sectorsize * m);
425 /* If the masterkey is all zeros, user destroyed it */
427 for (i = 0; i < (int)sizeof(gl->mkey); i++)
432 /* If we have an unsorted lock-sequence, refuse */
433 for (i = 0; i < G_BDE_MAXKEYS - 1; i++)
434 if (gl->lsector[i] >= gl->lsector[i + 1])
437 /* Finally, find out which key was used by matching the byte offset */
438 for (i = 0; i < G_BDE_MAXKEYS; i++)
439 if (nkey != NULL && off == gl->lsector[i])
446 g_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
448 u_char *buf, buf1[16];
451 /* set up the key-material */
452 bcopy(keymat, sc->sha2, SHA512_DIGEST_LENGTH);
454 /* If passed-in metadata is non-zero, use it */
455 bzero(buf1, sizeof buf1);
456 if (meta != NULL && bcmp(buf1, meta, sizeof buf1))
457 return (g_bde_decrypt_lockx(sc, meta, mediasize,
460 /* Read sector zero */
461 buf = g_read_data(sc->consumer, 0, sectorsize, &error);
465 /* Try each index in turn, save indicative errors for final result */
467 for (i = 0; i < G_BDE_MAXKEYS; i++) {
468 e = g_bde_decrypt_lockx(sc, buf + i * 16, mediasize,
470 /* Success or destroyed master key terminates */
471 if (e == 0 || e == ENOENT) {
475 if (e != 0 && error == EINVAL)