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$
33139778Simp */
34139778Simp/* 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/lock.h>
42105464Sphk#include <sys/mutex.h>
43113010Sphk#include <sys/endian.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
60143418Sume#include <crypto/rijndael/rijndael-api-fst.h>
61292782Sallanjude#include <crypto/sha2/sha512.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
127120876Sphkg_bde_shuffle_lock(u_char *sha2, 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 */
137120876Sphk	for(u = 48; u < SHA512_DIGEST_LENGTH; u++) {
138120876Sphk		j = sha2[u] % NLOCK_FIELDS;
139120876Sphk		k = (sha2[u] / NLOCK_FIELDS) % NLOCK_FIELDS;
140106407Sphk		l = buf[j];
141106407Sphk		buf[j] = buf[k];
142106407Sphk		buf[k] = l;
143106407Sphk	}
144105464Sphk}
145105464Sphk
146106407Sphkint
147120876Sphkg_bde_encode_lock(u_char *sha2, 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;
156120876Sphk	g_bde_shuffle_lock(sha2, shuffle);
157106407Sphk	for (i = 0; i < NLOCK_FIELDS; i++) {
158106407Sphk		switch(shuffle[i]) {
159106407Sphk		case 0:
160113010Sphk			le64enc(p, gl->sector0);
161106407Sphk			p += 8;
162106407Sphk			break;
163106407Sphk		case 1:
164113010Sphk			le64enc(p, gl->sectorN);
165106407Sphk			p += 8;
166106407Sphk			break;
167106407Sphk		case 2:
168113010Sphk			le64enc(p, gl->keyoffset);
169106407Sphk			p += 8;
170106407Sphk			break;
171106407Sphk		case 3:
172113010Sphk			le32enc(p, gl->sectorsize);
173106407Sphk			p += 4;
174106407Sphk			break;
175106407Sphk		case 4:
176113010Sphk			le32enc(p, gl->flags);
177106407Sphk			p += 4;
178106407Sphk			break;
179106407Sphk		case 5:
180106407Sphk		case 6:
181106407Sphk		case 7:
182106407Sphk		case 8:
183113010Sphk			le64enc(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;
226120876Sphk	g_bde_shuffle_lock(sc->sha2, shuffle);
227106407Sphk	for (i = 0; i < NLOCK_FIELDS; i++) {
228106407Sphk		switch(shuffle[i]) {
229106407Sphk		case 0:
230113010Sphk			gl->sector0 = le64dec(p);
231106407Sphk			p += 8;
232106407Sphk			break;
233106407Sphk		case 1:
234113010Sphk			gl->sectorN = le64dec(p);
235106407Sphk			p += 8;
236106407Sphk			break;
237106407Sphk		case 2:
238113010Sphk			gl->keyoffset = le64dec(p);
239106407Sphk			p += 8;
240106407Sphk			break;
241106407Sphk		case 3:
242113010Sphk			gl->sectorsize = le32dec(p);
243106407Sphk			p += 4;
244106407Sphk			break;
245106407Sphk		case 4:
246113010Sphk			gl->flags = le32dec(p);
247106407Sphk			p += 4;
248106407Sphk			break;
249106407Sphk		case 5:
250106407Sphk		case 6:
251106407Sphk		case 7:
252106407Sphk		case 8:
253113010Sphk			gl->lsector[shuffle[i] - 5] = le64dec(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
292298808Spfg * in the same endianness 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
306120876Sphkg_bde_keyloc_encrypt(u_char *sha2, uint64_t v0, uint64_t v1, void *output)
307105464Sphk{
308106407Sphk	u_char buf[16];
309105464Sphk	keyInstance ki;
310105464Sphk	cipherInstance ci;
311105464Sphk
312120876Sphk	le64enc(buf, v0);
313120876Sphk	le64enc(buf + 8, v1);
314106407Sphk	AES_init(&ci);
315120876Sphk	AES_makekey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, 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
324120876Sphkg_bde_keyloc_decrypt(u_char *sha2, void *input, uint64_t *output)
325105464Sphk{
326105464Sphk	keyInstance ki;
327105464Sphk	cipherInstance ci;
328106407Sphk	u_char buf[16];
329105464Sphk
330106407Sphk	AES_init(&ci);
331120876Sphk	AES_makekey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, sha2 + 0);
332106407Sphk	AES_decrypt(&ci, &ki, input, buf, sizeof buf);
333120876Sphk	*output = le64dec(buf);
334106407Sphk	bzero(buf, sizeof buf);
335105464Sphk	bzero(&ci, sizeof ci);
336105512Sphk	bzero(&ki, sizeof ki);
337120876Sphk	return(0);
338105464Sphk}
339105464Sphk
340105464Sphk/*
341106407Sphk * Find and Encode/Decode lock sectors.
342106407Sphk *
343106407Sphk * Security objective: given the pass-phrase, find, decrypt, decode and
344106407Sphk * validate the lock sector contents.
345106407Sphk *
346106407Sphk * For ondisk metadata we cannot know beforehand which of the lock sectors
347106407Sphk * a given pass-phrase opens so we must try each of the metadata copies in
348106407Sphk * sector zero in turn.  If metadata was passed as an argument, we don't
349106407Sphk * have this problem.
350106407Sphk *
351105464Sphk */
352105464Sphk
353105512Sphkstatic int
354106407Sphkg_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
355105464Sphk{
356106407Sphk	u_char *buf, *q;
357105464Sphk	struct g_bde_key *gl;
358120876Sphk	uint64_t off, q1;
359105464Sphk	int error, m, i;
360105464Sphk	keyInstance ki;
361105464Sphk	cipherInstance ci;
362105464Sphk
363105464Sphk	gl = &sc->key;
364106407Sphk
365106407Sphk	/* Try to decrypt the metadata */
366120876Sphk	error = g_bde_keyloc_decrypt(sc->sha2, meta, &off);
367105464Sphk	if (error)
368120876Sphk		return (error);
369105464Sphk
370138888Sbrueffer	/* If it points into thin blue air, forget it */
371120876Sphk	if (off + G_BDE_LOCKSIZE > (uint64_t)mediasize) {
372120876Sphk		off = 0;
373105512Sphk		return (EINVAL);
374105464Sphk	}
375106407Sphk
376106407Sphk	/* The lock data may span two physical sectors. */
377106407Sphk
378105464Sphk	m = 1;
379120876Sphk	if (off % sectorsize > sectorsize - G_BDE_LOCKSIZE)
380105464Sphk		m++;
381106407Sphk
382106407Sphk	/* Read the suspected sector(s) */
383105464Sphk	buf = g_read_data(sc->consumer,
384120876Sphk		off - (off % sectorsize),
385105464Sphk		m * sectorsize, &error);
386105464Sphk	if (buf == NULL) {
387120876Sphk		off = 0;
388105464Sphk		return(error);
389105464Sphk	}
390105464Sphk
391106407Sphk	/* Find the byte-offset of the stored byte sequence */
392120876Sphk	q = buf + off % sectorsize;
393105464Sphk
394106407Sphk	/* If it is all zero, somebody nuked our lock sector */
395120876Sphk	q1 = 0;
396105512Sphk	for (i = 0; i < G_BDE_LOCKSIZE; i++)
397120876Sphk		q1 += q[i];
398120876Sphk	if (q1 == 0) {
399120876Sphk		off = 0;
400105464Sphk		g_free(buf);
401105464Sphk		return (ESRCH);
402105464Sphk	}
403105464Sphk
404106407Sphk	/* Decrypt the byte-sequence in place */
405106407Sphk	AES_init(&ci);
406106407Sphk	AES_makekey(&ki, DIR_DECRYPT, 256, sc->sha2 + 16);
407106407Sphk	AES_decrypt(&ci, &ki, q, q, G_BDE_LOCKSIZE);
408152966Ssobomax
409106407Sphk	/* Decode the byte-sequence */
410106407Sphk	i = g_bde_decode_lock(sc, gl, q);
411106407Sphk	q = NULL;
412106407Sphk	if (i < 0) {
413120876Sphk		off = 0;
414106407Sphk		return (EDOOFUS);	/* Programming error */
415106407Sphk	} else if (i > 0) {
416120876Sphk		off = 0;
417106407Sphk		return (ENOTDIR);	/* Hash didn't match */
418105464Sphk	}
419105464Sphk
420105464Sphk	bzero(buf, sectorsize * m);
421105464Sphk	g_free(buf);
422105464Sphk
423106407Sphk	/* If the masterkey is all zeros, user destroyed it */
424120876Sphk	q1 = 0;
425106226Sphk	for (i = 0; i < (int)sizeof(gl->mkey); i++)
426120876Sphk		q1 += gl->mkey[i];
427120876Sphk	if (q1 == 0)
428106407Sphk		return (ENOENT);
429105464Sphk
430108052Sphk	/* If we have an unsorted lock-sequence, refuse */
431135084Sphk	for (i = 0; i < G_BDE_MAXKEYS - 1; i++)
432135084Sphk		if (gl->lsector[i] >= gl->lsector[i + 1])
433135084Sphk			return (EINVAL);
434108052Sphk
435106407Sphk	/* Finally, find out which key was used by matching the byte offset */
436105464Sphk	for (i = 0; i < G_BDE_MAXKEYS; i++)
437120876Sphk		if (nkey != NULL && off == gl->lsector[i])
438105464Sphk			*nkey = i;
439120876Sphk	off = 0;
440105464Sphk	return (0);
441105464Sphk}
442105512Sphk
443105512Sphkint
444106407Sphkg_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey)
445105512Sphk{
446105512Sphk	u_char *buf, buf1[16];
447105512Sphk	int error, e, i;
448105512Sphk
449106407Sphk	/* set up the key-material */
450106407Sphk	bcopy(keymat, sc->sha2, SHA512_DIGEST_LENGTH);
451106407Sphk
452106407Sphk	/* If passed-in metadata is non-zero, use it */
453105512Sphk	bzero(buf1, sizeof buf1);
454112594Sphk	if (meta != NULL && bcmp(buf1, meta, sizeof buf1))
455106407Sphk		return (g_bde_decrypt_lockx(sc, meta, mediasize,
456105512Sphk		    sectorsize, nkey));
457105512Sphk
458106407Sphk	/* Read sector zero */
459105512Sphk	buf = g_read_data(sc->consumer, 0, sectorsize, &error);
460105512Sphk	if (buf == NULL)
461105512Sphk		return(error);
462106407Sphk
463106407Sphk	/* Try each index in turn, save indicative errors for final result */
464106407Sphk	error = EINVAL;
465105512Sphk	for (i = 0; i < G_BDE_MAXKEYS; i++) {
466106407Sphk		e = g_bde_decrypt_lockx(sc, buf + i * 16, mediasize,
467105512Sphk		    sectorsize, nkey);
468106407Sphk		/* Success or destroyed master key terminates */
469105512Sphk		if (e == 0 || e == ENOENT) {
470105512Sphk			error = e;
471105512Sphk			break;
472105512Sphk		}
473106407Sphk		if (e != 0 && error == EINVAL)
474105512Sphk			error = e;
475105512Sphk	}
476105512Sphk	g_free(buf);
477105512Sphk	return (error);
478105512Sphk}
479