2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 /* This souce file contains routines which operates on the lock sectors, both
35 * for the kernel and the userland program gbde(1).
39 #include <sys/param.h>
40 #include <sys/queue.h>
42 #include <sys/mutex.h>
43 #include <sys/endian.h>
47 #include <sys/malloc.h>
48 #include <sys/systm.h>
52 #define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0)
57 #define g_free(foo) free(foo)
60 #include <crypto/rijndael/rijndael-api-fst.h>
61 #include <crypto/sha2/sha512.h>
63 #include <geom/geom.h>
64 #include <geom/bde/g_bde.h>
67 * Hash the raw pass-phrase.
69 * Security objectives: produce from the pass-phrase a fixed length
70 * bytesequence with PRN like properties in a reproducible way retaining
71 * as much entropy from the pass-phrase as possible.
73 * SHA2-512 makes this easy.
77 g_bde_hash_pass(struct g_bde_softc
*sc
, const void *input
, u_int len
)
82 SHA512_Update(&cx
, input
, len
);
83 SHA512_Final(sc
->sha2
, &cx
);
87 * Encode/Decode the lock structure in byte-sequence format.
89 * Security objectives: Store in pass-phrase dependent variant format.
91 * C-structure packing and byte-endianess depends on architecture, compiler
92 * and compiler options. Writing raw structures to disk is therefore a bad
93 * idea in these enlightend days.
95 * We spend a fraction of the key-material on shuffling the fields around
96 * so they will be stored in an unpredictable sequence.
98 * For each byte of the key-material we derive two field indexes, and swap
99 * the position of those two fields.
101 * I have not worked out the statistical properties of this shuffle, but
102 * given that the key-material has PRN properties, the primary objective
103 * of making it hard to figure out which bits are where in the lock sector
104 * is sufficiently fulfilled.
106 * We include (and shuffle) an extra hash field in the stored version for
107 * identification and versioning purposes. This field contains the MD5 hash
108 * of a version identifier (currently "0000") followed by the stored lock
109 * sector byte-sequence substituting zero bytes for the hash field.
111 * The stored keysequence is protected by AES/256/CBC elsewhere in the code
112 * so the fact that the generated byte sequence has a much higher than
113 * average density of zero bits (from the numeric fields) is not currently
116 * Should this later become a concern, a simple software update and
117 * pass-phrase change can remedy the situation. One possible solution
118 * could be to XOR the numeric fields with a key-material derived PRN.
120 * The chosen shuffle algorithm only works as long as we have no more than 16
121 * fields in the stored part of the lock structure (hence the CTASSERT below).
124 CTASSERT(NLOCK_FIELDS
<= 16);
127 g_bde_shuffle_lock(u_char
*sha2
, int *buf
)
132 /* Assign the fields sequential positions */
133 for(u
= 0; u
< NLOCK_FIELDS
; u
++)
136 /* Then mix it all up */
137 for(u
= 48; u
< SHA512_DIGEST_LENGTH
; u
++) {
138 j
= sha2
[u
] % NLOCK_FIELDS
;
139 k
= (sha2
[u
] / NLOCK_FIELDS
) % NLOCK_FIELDS
;
147 g_bde_encode_lock(u_char
*sha2
, struct g_bde_key
*gl
, u_char
*ptr
)
149 int shuffle
[NLOCK_FIELDS
];
156 g_bde_shuffle_lock(sha2
, shuffle
);
157 for (i
= 0; i
< NLOCK_FIELDS
; i
++) {
160 le64enc(p
, gl
->sector0
);
164 le64enc(p
, gl
->sectorN
);
168 le64enc(p
, gl
->keyoffset
);
172 le32enc(p
, gl
->sectorsize
);
176 le32enc(p
, gl
->flags
);
183 le64enc(p
, gl
->lsector
[shuffle
[i
] - 5]);
187 bcopy(gl
->spare
, p
, sizeof gl
->spare
);
188 p
+= sizeof gl
->spare
;
191 bcopy(gl
->salt
, p
, sizeof gl
->salt
);
192 p
+= sizeof gl
->salt
;
195 bcopy(gl
->mkey
, p
, sizeof gl
->mkey
);
196 p
+= sizeof gl
->mkey
;
205 if(ptr
+ G_BDE_LOCKSIZE
!= p
)
210 MD5Update(&c
, "0000", 4); /* Versioning */
211 MD5Update(&c
, ptr
, G_BDE_LOCKSIZE
);
217 g_bde_decode_lock(struct g_bde_softc
*sc
, struct g_bde_key
*gl
, u_char
*ptr
)
219 int shuffle
[NLOCK_FIELDS
];
221 u_char hash
[16], hash2
[16];
226 g_bde_shuffle_lock(sc
->sha2
, shuffle
);
227 for (i
= 0; i
< NLOCK_FIELDS
; i
++) {
230 gl
->sector0
= le64dec(p
);
234 gl
->sectorN
= le64dec(p
);
238 gl
->keyoffset
= le64dec(p
);
242 gl
->sectorsize
= le32dec(p
);
246 gl
->flags
= le32dec(p
);
253 gl
->lsector
[shuffle
[i
] - 5] = le64dec(p
);
257 bcopy(p
, gl
->spare
, sizeof gl
->spare
);
258 p
+= sizeof gl
->spare
;
261 bcopy(p
, gl
->salt
, sizeof gl
->salt
);
262 p
+= sizeof gl
->salt
;
265 bcopy(p
, gl
->mkey
, sizeof gl
->mkey
);
266 p
+= sizeof gl
->mkey
;
269 bcopy(p
, hash2
, sizeof hash2
);
270 bzero(p
, sizeof hash2
);
275 if(ptr
+ G_BDE_LOCKSIZE
!= p
)
278 MD5Update(&c
, "0000", 4); /* Versioning */
279 MD5Update(&c
, ptr
, G_BDE_LOCKSIZE
);
281 if (bcmp(hash
, hash2
, sizeof hash2
))
287 * Encode/Decode the locksector address ("metadata") with key-material.
289 * Security objectives: Encode/Decode the metadata encrypted by key-material.
291 * A simple AES/128/CBC will do. We take care to always store the metadata
292 * in the same endianness to make it MI.
294 * In the typical case the metadata is stored in encrypted format in sector
295 * zero on the media, but at the users discretion or if the piece of the
296 * device used (sector0...sectorN) does not contain sector zero, it can
297 * be stored in a filesystem or on a PostIt.
299 * The inability to easily locate the lock sectors makes an attack on a
300 * cold disk much less attractive, without unduly inconveniencing the
301 * legitimate user who can feasibly do a brute-force scan if the metadata
306 g_bde_keyloc_encrypt(u_char
*sha2
, uint64_t v0
, uint64_t v1
, void *output
)
313 le64enc(buf
+ 8, v1
);
315 AES_makekey(&ki
, DIR_ENCRYPT
, G_BDE_KKEYBITS
, sha2
+ 0);
316 AES_encrypt(&ci
, &ki
, buf
, output
, sizeof buf
);
317 bzero(buf
, sizeof buf
);
318 bzero(&ci
, sizeof ci
);
319 bzero(&ki
, sizeof ki
);
324 g_bde_keyloc_decrypt(u_char
*sha2
, void *input
, uint64_t *output
)
331 AES_makekey(&ki
, DIR_DECRYPT
, G_BDE_KKEYBITS
, sha2
+ 0);
332 AES_decrypt(&ci
, &ki
, input
, buf
, sizeof buf
);
333 *output
= le64dec(buf
);
334 bzero(buf
, sizeof buf
);
335 bzero(&ci
, sizeof ci
);
336 bzero(&ki
, sizeof ki
);
341 * Find and Encode/Decode lock sectors.
343 * Security objective: given the pass-phrase, find, decrypt, decode and
344 * validate the lock sector contents.
346 * For ondisk metadata we cannot know beforehand which of the lock sectors
347 * a given pass-phrase opens so we must try each of the metadata copies in
348 * sector zero in turn. If metadata was passed as an argument, we don't
354 g_bde_decrypt_lockx(struct g_bde_softc
*sc
, u_char
*meta
, off_t mediasize
, u_int sectorsize
, u_int
*nkey
)
357 struct g_bde_key
*gl
;
365 /* Try to decrypt the metadata */
366 error
= g_bde_keyloc_decrypt(sc
->sha2
, meta
, &off
);
370 /* If it points into thin blue air, forget it */
371 if (off
+ G_BDE_LOCKSIZE
> (uint64_t)mediasize
) {
376 /* The lock data may span two physical sectors. */
379 if (off
% sectorsize
> sectorsize
- G_BDE_LOCKSIZE
)
382 /* Read the suspected sector(s) */
383 buf
= g_read_data(sc
->consumer
,
384 off
- (off
% sectorsize
),
385 m
* sectorsize
, &error
);
391 /* Find the byte-offset of the stored byte sequence */
392 q
= buf
+ off
% sectorsize
;
394 /* If it is all zero, somebody nuked our lock sector */
396 for (i
= 0; i
< G_BDE_LOCKSIZE
; i
++)
404 /* Decrypt the byte-sequence in place */
406 AES_makekey(&ki
, DIR_DECRYPT
, 256, sc
->sha2
+ 16);
407 AES_decrypt(&ci
, &ki
, q
, q
, G_BDE_LOCKSIZE
);
409 /* Decode the byte-sequence */
410 i
= g_bde_decode_lock(sc
, gl
, q
);
414 return (EDOOFUS
); /* Programming error */
417 return (ENOTDIR
); /* Hash didn't match */
420 bzero(buf
, sectorsize
* m
);
423 /* If the masterkey is all zeros, user destroyed it */
425 for (i
= 0; i
< (int)sizeof(gl
->mkey
); i
++)
430 /* If we have an unsorted lock-sequence, refuse */
431 for (i
= 0; i
< G_BDE_MAXKEYS
- 1; i
++)
432 if (gl
->lsector
[i
] >= gl
->lsector
[i
+ 1])
435 /* Finally, find out which key was used by matching the byte offset */
436 for (i
= 0; i
< G_BDE_MAXKEYS
; i
++)
437 if (nkey
!= NULL
&& off
== gl
->lsector
[i
])
444 g_bde_decrypt_lock(struct g_bde_softc
*sc
, u_char
*keymat
, u_char
*meta
, off_t mediasize
, u_int sectorsize
, u_int
*nkey
)
446 u_char
*buf
, buf1
[16];
449 /* set up the key-material */
450 bcopy(keymat
, sc
->sha2
, SHA512_DIGEST_LENGTH
);
452 /* If passed-in metadata is non-zero, use it */
453 bzero(buf1
, sizeof buf1
);
454 if (meta
!= NULL
&& bcmp(buf1
, meta
, sizeof buf1
))
455 return (g_bde_decrypt_lockx(sc
, meta
, mediasize
,
458 /* Read sector zero */
459 buf
= g_read_data(sc
->consumer
, 0, sectorsize
, &error
);
463 /* Try each index in turn, save indicative errors for final result */
465 for (i
= 0; i
< G_BDE_MAXKEYS
; i
++) {
466 e
= g_bde_decrypt_lockx(sc
, buf
+ i
* 16, mediasize
,
468 /* Success or destroyed master key terminates */
469 if (e
== 0 || e
== ENOENT
) {
473 if (e
!= 0 && error
== EINVAL
)