g_bde_lock.c revision 108052
1105464Sphk/*-
2105464Sphk * Copyright (c) 2002 Poul-Henning Kamp
3105464Sphk * Copyright (c) 2002 Networks Associates Technology, Inc.
4105464Sphk * All rights reserved.
5105464Sphk *
6105464Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7105464Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc.
8105464Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9105464Sphk * DARPA CHATS research program.
10105464Sphk *
11105464Sphk * Redistribution and use in source and binary forms, with or without
12105464Sphk * modification, are permitted provided that the following conditions
13105464Sphk * are met:
14105464Sphk * 1. Redistributions of source code must retain the above copyright
15105464Sphk *    notice, this list of conditions and the following disclaimer.
16105464Sphk * 2. Redistributions in binary form must reproduce the above copyright
17105464Sphk *    notice, this list of conditions and the following disclaimer in the
18105464Sphk *    documentation and/or other materials provided with the distribution.
19105464Sphk *
20105464Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21105464Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22105464Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23105464Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24105464Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25105464Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26105464Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27105464Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28105464Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29105464Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30105464Sphk * SUCH DAMAGE.
31105464Sphk *
32105464Sphk * $FreeBSD: head/sys/geom/bde/g_bde_lock.c 108052 2002-12-18 19:57:27Z phk $
33105464Sphk *
34105464Sphk * This souce file contains routines which operates on the lock sectors, both
35105464Sphk * for the kernel and the userland program gbde(1).
36105464Sphk *
37105464Sphk */
38105464Sphk
39105464Sphk#include <sys/param.h>
40105464Sphk#include <sys/queue.h>
41105464Sphk#include <sys/stdint.h>
42105464Sphk#include <sys/lock.h>
43105464Sphk#include <sys/mutex.h>
44105464Sphk#include <sys/md5.h>
45105464Sphk
46105464Sphk#ifdef _KERNEL
47105464Sphk#include <sys/malloc.h>
48105464Sphk#include <sys/systm.h>
49105464Sphk#else
50106407Sphk#include <err.h>
51106407Sphk#define CTASSERT(foo)
52106407Sphk#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0)
53105464Sphk#include <errno.h>
54105464Sphk#include <string.h>
55105464Sphk#include <stdlib.h>
56105464Sphk#include <stdio.h>
57105464Sphk#define g_free(foo)	free(foo)
58105464Sphk#endif
59105464Sphk
60106407Sphk#include <crypto/rijndael/rijndael.h>
61106407Sphk#include <crypto/sha2/sha2.h>
62106407Sphk
63105464Sphk#include <geom/geom.h>
64105464Sphk#include <geom/bde/g_bde.h>
65105464Sphk
66105464Sphk/*
67106407Sphk * Hash the raw pass-phrase.
68105464Sphk *
69106407Sphk * Security objectives: produce from the pass-phrase a fixed length
70106407Sphk * bytesequence with PRN like properties in a reproducible way retaining
71106407Sphk * as much entropy from the pass-phrase as possible.
72105464Sphk *
73106407Sphk * SHA2-512 makes this easy.
74105464Sphk */
75105464Sphk
76105464Sphkvoid
77106407Sphkg_bde_hash_pass(struct g_bde_softc *sc, const void *input, u_int len)
78105464Sphk{
79106407Sphk	SHA512_CTX cx;
80105464Sphk
81106407Sphk	SHA512_Init(&cx);
82106407Sphk	SHA512_Update(&cx, input, len);
83106407Sphk	SHA512_Final(sc->sha2, &cx);
84105464Sphk}
85105464Sphk
86105464Sphk/*
87106407Sphk * Encode/Decode the lock structure in byte-sequence format.
88105464Sphk *
89106407Sphk * Security objectives: Store in pass-phrase dependent variant format.
90105464Sphk *
91106407Sphk * C-structure packing and byte-endianess depends on architecture, compiler
92106407Sphk * and compiler options.  Writing raw structures to disk is therefore a bad
93106407Sphk * idea in these enlightend days.
94106407Sphk *
95106407Sphk * We spend a fraction of the key-material on shuffling the fields around
96106407Sphk * so they will be stored in an unpredictable sequence.
97106407Sphk *
98106407Sphk * For each byte of the key-material we derive two field indexes, and swap
99106407Sphk * the position of those two fields.
100106407Sphk *
101106407Sphk * I have not worked out the statistical properties of this shuffle, but
102106407Sphk * given that the key-material has PRN properties, the primary objective
103106407Sphk * of making it hard to figure out which bits are where in the lock sector
104106407Sphk * is sufficiently fulfilled.
105106407Sphk *
106106407Sphk * We include (and shuffle) an extra hash field in the stored version for
107106407Sphk * identification and versioning purposes.  This field contains the MD5 hash
108106407Sphk * of a version identifier (currently "0000") followed by the stored lock
109106407Sphk * sector byte-sequence substituting zero bytes for the hash field.
110106407Sphk *
111106407Sphk * The stored keysequence is protected by AES/256/CBC elsewhere in the code
112106407Sphk * so the fact that the generated byte sequence has a much higher than
113106407Sphk * average density of zero bits (from the numeric fields) is not currently
114106407Sphk * a concern.
115106407Sphk *
116106407Sphk * Should this later become a concern, a simple software update and
117106407Sphk * pass-phrase change can remedy the situation.  One possible solution
118106407Sphk * could be to XOR the numeric fields with a key-material derived PRN.
119106407Sphk *
120106407Sphk * The chosen shuffle algorithm only works as long as we have no more than 16
121106407Sphk * fields in the stored part of the lock structure (hence the CTASSERT below).
122105464Sphk */
123105464Sphk
124106407SphkCTASSERT(NLOCK_FIELDS <= 16);
125106407Sphk
126106407Sphkstatic void
127106407Sphkg_bde_shuffle_lock(struct g_bde_softc *sc, int *buf)
128105464Sphk{
129107450Sphk	int j, k, l;
130107450Sphk	u_int u;
131105464Sphk
132106407Sphk	/* Assign the fields sequential positions */
133107450Sphk	for(u = 0; u < NLOCK_FIELDS; u++)
134107450Sphk		buf[u] = u;
135106407Sphk
136106407Sphk	/* Then mix it all up */
137107450Sphk	for(u = 48; u < sizeof(sc->sha2); u++) {
138107450Sphk		j = sc->sha2[u] % NLOCK_FIELDS;
139107450Sphk		k = (sc->sha2[u] / NLOCK_FIELDS) % NLOCK_FIELDS;
140106407Sphk		l = buf[j];
141106407Sphk		buf[j] = buf[k];
142106407Sphk		buf[k] = l;
143106407Sphk	}
144105464Sphk}
145105464Sphk
146106407Sphkint
147106407Sphkg_bde_encode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
148105464Sphk{
149106407Sphk	int shuffle[NLOCK_FIELDS];
150106407Sphk	u_char *hash, *p;
151106407Sphk	int i;
152106407Sphk	MD5_CTX c;
153106407Sphk
154105464Sphk	p = ptr;
155106407Sphk	hash = NULL;
156106407Sphk	g_bde_shuffle_lock(sc, shuffle);
157106407Sphk	for (i = 0; i < NLOCK_FIELDS; i++) {
158106407Sphk		switch(shuffle[i]) {
159106407Sphk		case 0:
160106407Sphk			g_enc_le8(p, gl->sector0);
161106407Sphk			p += 8;
162106407Sphk			break;
163106407Sphk		case 1:
164106407Sphk			g_enc_le8(p, gl->sectorN);
165106407Sphk			p += 8;
166106407Sphk			break;
167106407Sphk		case 2:
168106407Sphk			g_enc_le8(p, gl->keyoffset);
169106407Sphk			p += 8;
170106407Sphk			break;
171106407Sphk		case 3:
172106407Sphk			g_enc_le4(p, gl->sectorsize);
173106407Sphk			p += 4;
174106407Sphk			break;
175106407Sphk		case 4:
176106407Sphk			g_enc_le4(p, gl->flags);
177106407Sphk			p += 4;
178106407Sphk			break;
179106407Sphk		case 5:
180106407Sphk		case 6:
181106407Sphk		case 7:
182106407Sphk		case 8:
183106407Sphk			g_enc_le8(p, gl->lsector[shuffle[i] - 5]);
184106407Sphk			p += 8;
185106407Sphk			break;
186106407Sphk		case 9:
187106407Sphk			bcopy(gl->spare, p, sizeof gl->spare);
188106407Sphk			p += sizeof gl->spare;
189106407Sphk			break;
190106407Sphk		case 10:
191106407Sphk			bcopy(gl->salt, p, sizeof gl->salt);
192106407Sphk			p += sizeof gl->salt;
193106407Sphk			break;
194106407Sphk		case 11:
195106407Sphk			bcopy(gl->mkey, p, sizeof gl->mkey);
196106407Sphk			p += sizeof gl->mkey;
197106407Sphk			break;
198106407Sphk		case 12:
199106407Sphk			bzero(p, 16);
200106407Sphk			hash = p;
201106407Sphk			p += 16;
202106407Sphk			break;
203106407Sphk		}
204106407Sphk	}
205106407Sphk	if(ptr + G_BDE_LOCKSIZE != p)
206106407Sphk		return(-1);
207106407Sphk	if (hash == NULL)
208106407Sphk		return(-1);
209106407Sphk	MD5Init(&c);
210106407Sphk	MD5Update(&c, "0000", 4);	/* Versioning */
211106407Sphk	MD5Update(&c, ptr, G_BDE_LOCKSIZE);
212106407Sphk	MD5Final(hash, &c);
213106407Sphk	return(0);
214105464Sphk}
215105464Sphk
216106407Sphkint
217106407Sphkg_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr)
218105464Sphk{
219106407Sphk	int shuffle[NLOCK_FIELDS];
220106407Sphk	u_char *p;
221106407Sphk	u_char hash[16], hash2[16];
222106407Sphk	MD5_CTX c;
223106407Sphk	int i;
224105464Sphk
225105464Sphk	p = ptr;
226106407Sphk	g_bde_shuffle_lock(sc, shuffle);
227106407Sphk	for (i = 0; i < NLOCK_FIELDS; i++) {
228106407Sphk		switch(shuffle[i]) {
229106407Sphk		case 0:
230106407Sphk			gl->sector0 = g_dec_le8(p);
231106407Sphk			p += 8;
232106407Sphk			break;
233106407Sphk		case 1:
234106407Sphk			gl->sectorN = g_dec_le8(p);
235106407Sphk			p += 8;
236106407Sphk			break;
237106407Sphk		case 2:
238106407Sphk			gl->keyoffset = g_dec_le8(p);
239106407Sphk			p += 8;
240106407Sphk			break;
241106407Sphk		case 3:
242106407Sphk			gl->sectorsize = g_dec_le4(p);
243106407Sphk			p += 4;
244106407Sphk			break;
245106407Sphk		case 4:
246106407Sphk			gl->flags = g_dec_le4(p);
247106407Sphk			p += 4;
248106407Sphk			break;
249106407Sphk		case 5:
250106407Sphk		case 6:
251106407Sphk		case 7:
252106407Sphk		case 8:
253106407Sphk			gl->lsector[shuffle[i] - 5] = g_dec_le8(p);
254106407Sphk			p += 8;
255106407Sphk			break;
256106407Sphk		case 9:
257106407Sphk			bcopy(p, gl->spare, sizeof gl->spare);
258106407Sphk			p += sizeof gl->spare;
259106407Sphk			break;
260106407Sphk		case 10:
261106407Sphk			bcopy(p, gl->salt, sizeof gl->salt);
262106407Sphk			p += sizeof gl->salt;
263106407Sphk			break;
264106407Sphk		case 11:
265106407Sphk			bcopy(p, gl->mkey, sizeof gl->mkey);
266106407Sphk			p += sizeof gl->mkey;
267106407Sphk			break;
268106407Sphk		case 12:
269106407Sphk			bcopy(p, hash2, sizeof hash2);
270106407Sphk			bzero(p, sizeof hash2);
271106407Sphk			p += sizeof hash2;
272106407Sphk			break;
273106407Sphk		}
274105464Sphk	}
275106407Sphk	if(ptr + G_BDE_LOCKSIZE != p)
276106407Sphk		return(-1);
277106407Sphk	MD5Init(&c);
278106407Sphk	MD5Update(&c, "0000", 4);	/* Versioning */
279106407Sphk	MD5Update(&c, ptr, G_BDE_LOCKSIZE);
280106407Sphk	MD5Final(hash, &c);
281106407Sphk	if (bcmp(hash, hash2, sizeof hash2))
282106407Sphk		return (1);
283106407Sphk	return (0);
284105464Sphk}
285105464Sphk
286105464Sphk/*
287106407Sphk * Encode/Decode the locksector address ("metadata") with key-material.
288106407Sphk *
289106407Sphk * Security objectives: Encode/Decode the metadata encrypted by key-material.
290106407Sphk *
291106407Sphk * A simple AES/128/CBC will do.  We take care to always store the metadata
292106407Sphk * in the same endianess to make it MI.
293106407Sphk *
294106407Sphk * In the typical case the metadata is stored in encrypted format in sector
295106407Sphk * zero on the media, but at the users discretion or if the piece of the
296106407Sphk * device used (sector0...sectorN) does not contain sector zero, it can
297106407Sphk * be stored in a filesystem or on a PostIt.
298106407Sphk *
299106407Sphk * The inability to easily locate the lock sectors makes an attack on a
300106407Sphk * cold disk much less attractive, without unduly inconveniencing the
301106407Sphk * legitimate user who can feasibly do a brute-force scan if the metadata
302106407Sphk * was lost.
303105464Sphk */
304105464Sphk
305105464Sphkint
306106407Sphkg_bde_keyloc_encrypt(struct g_bde_softc *sc, uint64_t *input, void *output)
307105464Sphk{
308106407Sphk	u_char buf[16];
309105464Sphk	keyInstance ki;
310105464Sphk	cipherInstance ci;
311105464Sphk
312106407Sphk	g_enc_le8(buf, input[0]);
313106407Sphk	g_enc_le8(buf + 8, input[1]);
314106407Sphk	AES_init(&ci);
315106407Sphk	AES_makekey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, sc->sha2 + 0);
316106407Sphk	AES_encrypt(&ci, &ki, buf, output, sizeof buf);
317106407Sphk	bzero(buf, sizeof buf);
318105464Sphk	bzero(&ci, sizeof ci);
319105512Sphk	bzero(&ki, sizeof ki);
320105464Sphk	return (0);
321105464Sphk}
322105464Sphk
323105464Sphkint
324106407Sphkg_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, uint64_t *output)
325105464Sphk{
326105464Sphk	keyInstance ki;
327105464Sphk	cipherInstance ci;
328106407Sphk	u_char buf[16];
329105464Sphk
330106407Sphk	AES_init(&ci);
331106407Sphk	AES_makekey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, sc->sha2 + 0);
332106407Sphk	AES_decrypt(&ci, &ki, input, buf, sizeof buf);
333106407Sphk	output[0] = g_dec_le8(buf);
334106407Sphk	output[1] = g_dec_le8(buf + 8);
335106407Sphk	bzero(buf, sizeof buf);
336105464Sphk	bzero(&ci, sizeof ci);
337105512Sphk	bzero(&ki, sizeof ki);
338105464Sphk	return (0);
339105464Sphk}
340105464Sphk
341105464Sphk/*
342106407Sphk * Find and Encode/Decode lock sectors.
343106407Sphk *
344106407Sphk * Security objective: given the pass-phrase, find, decrypt, decode and
345106407Sphk * validate the lock sector contents.
346106407Sphk *
347106407Sphk * For ondisk metadata we cannot know beforehand which of the lock sectors
348106407Sphk * a given pass-phrase opens so we must try each of the metadata copies in
349106407Sphk * sector zero in turn.  If metadata was passed as an argument, we don't
350106407Sphk * have this problem.
351106407Sphk *
352105464Sphk */
353105464Sphk
354105512Sphkstatic int
355106407Sphkg_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
356105464Sphk{
357106407Sphk	u_char *buf, *q;
358105464Sphk	struct g_bde_key *gl;
359105464Sphk	uint64_t off[2];
360105464Sphk	int error, m, i;
361105464Sphk	keyInstance ki;
362105464Sphk	cipherInstance ci;
363105464Sphk
364105464Sphk	gl = &sc->key;
365106407Sphk
366106407Sphk	/* Try to decrypt the metadata */
367105464Sphk	error = g_bde_keyloc_decrypt(sc, meta, off);
368105464Sphk	if (error)
369105464Sphk		return(error);
370105464Sphk
371106407Sphk	/* loose the random part */
372106407Sphk	off[1] = 0;
373106407Sphk
374106407Sphk	/* If it points ito thin blue air, forget it */
375105464Sphk	if (off[0] + G_BDE_LOCKSIZE > (uint64_t)mediasize) {
376106407Sphk		off[0] = 0;
377105512Sphk		return (EINVAL);
378105464Sphk	}
379106407Sphk
380106407Sphk	/* The lock data may span two physical sectors. */
381106407Sphk
382105464Sphk	m = 1;
383105464Sphk	if (off[0] % sectorsize > sectorsize - G_BDE_LOCKSIZE)
384105464Sphk		m++;
385106407Sphk
386106407Sphk	/* Read the suspected sector(s) */
387105464Sphk	buf = g_read_data(sc->consumer,
388105464Sphk		off[0] - (off[0] % sectorsize),
389105464Sphk		m * sectorsize, &error);
390105464Sphk	if (buf == NULL) {
391105464Sphk		off[0] = 0;
392105464Sphk		return(error);
393105464Sphk	}
394105464Sphk
395106407Sphk	/* Find the byte-offset of the stored byte sequence */
396105464Sphk	q = buf + off[0] % sectorsize;
397105464Sphk
398106407Sphk	/* If it is all zero, somebody nuked our lock sector */
399105512Sphk	for (i = 0; i < G_BDE_LOCKSIZE; i++)
400105464Sphk		off[1] += q[i];
401105464Sphk	if (off[1] == 0) {
402105464Sphk		off[0] = 0;
403105464Sphk		g_free(buf);
404105464Sphk		return (ESRCH);
405105464Sphk	}
406105464Sphk
407106407Sphk	/* Decrypt the byte-sequence in place */
408106407Sphk	AES_init(&ci);
409106407Sphk	AES_makekey(&ki, DIR_DECRYPT, 256, sc->sha2 + 16);
410106407Sphk	AES_decrypt(&ci, &ki, q, q, G_BDE_LOCKSIZE);
411106407Sphk
412106407Sphk	/* Decode the byte-sequence */
413106407Sphk	i = g_bde_decode_lock(sc, gl, q);
414106407Sphk	q = NULL;
415106407Sphk	if (i < 0) {
416105464Sphk		off[0] = 0;
417106407Sphk		return (EDOOFUS);	/* Programming error */
418106407Sphk	} else if (i > 0) {
419106407Sphk		off[0] = 0;
420106407Sphk		return (ENOTDIR);	/* Hash didn't match */
421105464Sphk	}
422105464Sphk
423105464Sphk	bzero(buf, sectorsize * m);
424105464Sphk	g_free(buf);
425105464Sphk
426106407Sphk	/* If the masterkey is all zeros, user destroyed it */
427105464Sphk	off[1] = 0;
428106226Sphk	for (i = 0; i < (int)sizeof(gl->mkey); i++)
429106226Sphk		off[1] += gl->mkey[i];
430106407Sphk	if (off[1] == 0)
431106407Sphk		return (ENOENT);
432105464Sphk
433108052Sphk	/* If we have an unsorted lock-sequence, refuse */
434108052Sphk	if (gl->lsector[0] > gl->lsector[1] ||
435108052Sphk	    gl->lsector[1] > gl->lsector[2] ||
436108052Sphk	    gl->lsector[2] > gl->lsector[3])
437108052Sphk		return (EINVAL);
438108052Sphk
439106407Sphk	/* Finally, find out which key was used by matching the byte offset */
440105464Sphk	for (i = 0; i < G_BDE_MAXKEYS; i++)
441105464Sphk		if (nkey != NULL && off[0] == gl->lsector[i])
442105464Sphk			*nkey = i;
443106407Sphk	off[0] = 0;
444105464Sphk	return (0);
445105464Sphk}
446105512Sphk
447105512Sphkint
448106407Sphkg_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
449105512Sphk{
450105512Sphk	u_char *buf, buf1[16];
451105512Sphk	int error, e, i;
452105512Sphk
453106407Sphk	/* set up the key-material */
454106407Sphk	bcopy(keymat, sc->sha2, SHA512_DIGEST_LENGTH);
455106407Sphk
456106407Sphk	/* If passed-in metadata is non-zero, use it */
457105512Sphk	bzero(buf1, sizeof buf1);
458105512Sphk	if (bcmp(buf1, meta, sizeof buf1))
459106407Sphk		return (g_bde_decrypt_lockx(sc, meta, mediasize,
460105512Sphk		    sectorsize, nkey));
461105512Sphk
462106407Sphk	/* Read sector zero */
463105512Sphk	buf = g_read_data(sc->consumer, 0, sectorsize, &error);
464105512Sphk	if (buf == NULL)
465105512Sphk		return(error);
466106407Sphk
467106407Sphk	/* Try each index in turn, save indicative errors for final result */
468106407Sphk	error = EINVAL;
469105512Sphk	for (i = 0; i < G_BDE_MAXKEYS; i++) {
470106407Sphk		e = g_bde_decrypt_lockx(sc, buf + i * 16, mediasize,
471105512Sphk		    sectorsize, nkey);
472106407Sphk		/* Success or destroyed master key terminates */
473105512Sphk		if (e == 0 || e == ENOENT) {
474105512Sphk			error = e;
475105512Sphk			break;
476105512Sphk		}
477106407Sphk		if (e != 0 && error == EINVAL)
478105512Sphk			error = e;
479105512Sphk	}
480105512Sphk	g_free(buf);
481105512Sphk	return (error);
482105512Sphk}
483