geom_aes.c revision 98987
1168404Spjd/*-
2168404Spjd * Copyright (c) 2002 Poul-Henning Kamp
3168404Spjd * Copyright (c) 2002 Networks Associates Technology, Inc.
4168404Spjd * All rights reserved.
5168404Spjd *
6168404Spjd * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7168404Spjd * and NAI Labs, the Security Research Division of Network Associates, Inc.
8168404Spjd * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9168404Spjd * DARPA CHATS research program.
10168404Spjd *
11168404Spjd * Redistribution and use in source and binary forms, with or without
12168404Spjd * modification, are permitted provided that the following conditions
13168404Spjd * are met:
14168404Spjd * 1. Redistributions of source code must retain the above copyright
15168404Spjd *    notice, this list of conditions and the following disclaimer.
16168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
17168404Spjd *    notice, this list of conditions and the following disclaimer in the
18168404Spjd *    documentation and/or other materials provided with the distribution.
19168404Spjd * 3. The names of the authors may not be used to endorse or promote
20168404Spjd *    products derived from this software without specific prior written
21168404Spjd *    permission.
22219089Spjd *
23247585Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24246586Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27219089Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28219089Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33168404Spjd * SUCH DAMAGE.
34185029Spjd *
35168404Spjd * $FreeBSD: head/sys/geom/geom_aes.c 98987 2002-06-28 21:25:15Z phk $
36168404Spjd *
37185029Spjd * This method provides AES encryption with a compiled in key (default
38168404Spjd * all zeroes).
39168404Spjd *
40168404Spjd * XXX: This could probably save a lot of code by pretending to be a slicer.
41168404Spjd */
42168404Spjd
43168404Spjd#include <sys/param.h>
44168404Spjd#ifndef _KERNEL
45168404Spjd#include <stdio.h>
46168404Spjd#include <string.h>
47185029Spjd#include <stdlib.h>
48168404Spjd#include <signal.h>
49209962Smm#include <err.h>
50209962Smm#else
51209962Smm#include <sys/systm.h>
52209962Smm#include <sys/kernel.h>
53209962Smm#include <sys/conf.h>
54209962Smm#include <sys/bio.h>
55209962Smm#include <sys/malloc.h>
56209962Smm#include <sys/lock.h>
57185029Spjd#include <sys/mutex.h>
58185029Spjd#include <sys/libkern.h>
59168404Spjd#include <sys/md5.h>
60185029Spjd#include <sys/endian.h>
61168404Spjd#endif
62168404Spjd#include <sys/errno.h>
63185029Spjd#include <geom/geom.h>
64185029Spjd
65168404Spjd#include <crypto/rijndael/rijndael.h>
66185029Spjd
67185029Spjd#include <crypto/rijndael/rijndael.h>
68185029Spjd
69185029Spjd#define AES_CLASS_NAME "AES"
70185029Spjd
71185029Spjd#define MASTER_KEY_LENGTH	(1024/8)
72185029Spjd
73185029Spjdstatic u_char *aes_magic = "<<FreeBSD-GEOM-AES>>";
74168404Spjdstatic u_char *aes_magic_random = "<<FreeBSD-GEOM-AES-RANDOM>>";
75219089Spjdstatic u_char *aes_magic_test = "<<FreeBSD-GEOM-AES-TEST>>";
76219089Spjd
77219089Spjd
78219089Spjdstruct g_aes_softc {
79219089Spjd	enum {
80219089Spjd		KEY_ZERO,
81219089Spjd		KEY_RANDOM,
82219089Spjd		KEY_TEST
83219089Spjd	} keying;
84219089Spjd	u_int	sectorsize;
85185029Spjd	off_t	mediasize;
86185029Spjd	cipherInstance ci;
87185029Spjd	u_char master_key[MASTER_KEY_LENGTH];
88185029Spjd};
89185029Spjd
90185029Spjd/*
91185029Spjd * Generate a sectorkey from the masterkey and the offset position.
92185029Spjd *
93185029Spjd * For KEY_ZERO we just return a key of all zeros.
94185029Spjd *
95185029Spjd * We feed the sector byte offset, 16 bytes of the master-key and
96185029Spjd * the sector byte offset once more to MD5.
97185029Spjd * The sector byte offset is converted to little-endian format first
98185029Spjd * to support multi-architecture operation.
99219089Spjd * We use 16 bytes from the master-key starting at the logical sector
100246586Sdelphij * number modulus he length of the master-key.  If need be we wrap
101185029Spjd * around to the start of the master-key.
102185029Spjd */
103168404Spjd
104185029Spjdstatic void
105185029Spjdg_aes_makekey(struct g_aes_softc *sc, off_t off, keyInstance *ki, int dir)
106185029Spjd{
107185029Spjd	MD5_CTX cx;
108185029Spjd	u_int64_t u64;
109168404Spjd	u_int u, u1;
110224174Smm	u_char *p, buf[16];
111224174Smm
112224174Smm	if (sc->keying == KEY_ZERO) {
113224174Smm		rijndael_makeKey(ki, dir, 128, sc->master_key);
114243560Smm		return;
115224174Smm	}
116224174Smm	MD5Init(&cx);
117224174Smm	u64 = htole64(off);
118185029Spjd	MD5Update(&cx, (u_char *)&u64, sizeof(u64));
119185029Spjd	u = off / sc->sectorsize;
120185029Spjd	u %= sizeof sc->master_key;
121185029Spjd	p = sc->master_key + u;
122185029Spjd	if (u + 16 <= sizeof(sc->master_key)) {
123185029Spjd		MD5Update(&cx, p, 16);
124201143Sdelphij	} else {
125185029Spjd		u1 = sizeof sc->master_key - u;
126185029Spjd		MD5Update(&cx, p, u1);
127168404Spjd		MD5Update(&cx, sc->master_key, 16 - u1);
128185029Spjd		u1 = 0;				/* destroy evidence */
129185029Spjd	}
130185029Spjd	u = 0;					/* destroy evidence */
131185029Spjd	MD5Update(&cx, (u_char *)&u64, sizeof(u64));
132185029Spjd	u64 = 0;				/* destroy evidence */
133185029Spjd	MD5Final(buf, &cx);
134168404Spjd	bzero(&cx, sizeof cx);			/* destroy evidence */
135185029Spjd	rijndael_makeKey(ki, dir, 128, buf);
136185029Spjd	bzero(buf, sizeof buf);			/* destroy evidence */
137185029Spjd
138185029Spjd}
139185029Spjd
140185029Spjdstatic void
141168404Spjdg_aes_read_done(struct bio *bp)
142185029Spjd{
143185029Spjd	struct g_geom *gp;
144185029Spjd	struct g_aes_softc *sc;
145185029Spjd	u_char *p, *b, *e, *sb;
146185029Spjd	keyInstance dkey;
147185029Spjd	off_t o;
148185029Spjd
149185029Spjd	gp = bp->bio_from->geom;
150185029Spjd	sc = gp->softc;
151185029Spjd	sb = g_malloc(sc->sectorsize, M_WAITOK);
152185029Spjd	b = bp->bio_data;
153185029Spjd	e = bp->bio_data;
154185029Spjd	e += bp->bio_length;
155168404Spjd	o = bp->bio_offset - sc->sectorsize;
156185029Spjd	for (p = b; p < e; p += sc->sectorsize) {
157185029Spjd		g_aes_makekey(sc, o, &dkey, DIR_DECRYPT);
158185029Spjd		rijndael_blockDecrypt(&sc->ci, &dkey, p, sc->sectorsize * 8, sb);
159185029Spjd		bcopy(sb, p, sc->sectorsize);
160209962Smm		o += sc->sectorsize;
161219089Spjd	}
162185029Spjd	bzero(&dkey, sizeof dkey);		/* destroy evidence */
163185029Spjd	bzero(sb, sc->sectorsize);		/* destroy evidence */
164185029Spjd	g_free(sb);
165168404Spjd	g_std_done(bp);
166185029Spjd}
167185029Spjd
168185029Spjdstatic void
169185029Spjdg_aes_write_done(struct bio *bp)
170185029Spjd{
171168404Spjd	struct g_aes_softc *sc;
172219089Spjd	struct g_geom *gp;
173219089Spjd
174219089Spjd	gp = bp->bio_to->geom;
175219089Spjd	sc = gp->softc;
176219089Spjd	bzero(bp->bio_data, bp->bio_length);	/* destroy evidence */
177219089Spjd	g_free(bp->bio_data);
178185029Spjd	g_std_done(bp);
179185029Spjd}
180185029Spjd
181185029Spjdstatic void
182185029Spjdg_aes_start(struct bio *bp)
183185029Spjd{
184168404Spjd	struct g_geom *gp;
185185029Spjd	struct g_consumer *cp;
186185029Spjd	struct g_aes_softc *sc;
187185029Spjd	struct bio *bp2;
188185029Spjd	u_char *p1, *p2, *b, *e;
189185029Spjd	keyInstance ekey;
190185029Spjd	off_t o;
191168404Spjd
192219089Spjd	gp = bp->bio_to->geom;
193219089Spjd	cp = LIST_FIRST(&gp->consumer);
194219089Spjd	sc = gp->softc;
195219089Spjd	switch (bp->bio_cmd) {
196219089Spjd	case BIO_READ:
197219089Spjd		bp2 = g_clone_bio(bp);
198219089Spjd		bp2->bio_done = g_aes_read_done;
199185029Spjd		bp2->bio_offset += sc->sectorsize;
200219089Spjd		g_io_request(bp2, cp);
201185029Spjd		break;
202219089Spjd	case BIO_WRITE:
203219089Spjd		bp2 = g_clone_bio(bp);
204219089Spjd		bp2->bio_done = g_aes_write_done;
205219089Spjd		bp2->bio_offset += sc->sectorsize;
206219089Spjd		bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK);
207185029Spjd		b = bp->bio_data;
208185029Spjd		e = bp->bio_data;
209219089Spjd		e += bp->bio_length;
210219089Spjd		p2 = bp2->bio_data;
211219089Spjd		o = bp->bio_offset;
212219089Spjd		for (p1 = b; p1 < e; p1 += sc->sectorsize) {
213219089Spjd			g_aes_makekey(sc, o, &ekey, DIR_ENCRYPT);
214185029Spjd			rijndael_blockEncrypt(&sc->ci, &ekey,
215185029Spjd			    p1, sc->sectorsize * 8, p2);
216246586Sdelphij			p2 += sc->sectorsize;
217246586Sdelphij			o += sc->sectorsize;
218219089Spjd		}
219185029Spjd		bzero(&ekey, sizeof ekey);	/* destroy evidence */
220185029Spjd		g_io_request(bp2, cp);
221224174Smm		break;
222224174Smm	case BIO_GETATTR:
223243560Smm	case BIO_SETATTR:
224243560Smm		if (g_handleattr_off_t(bp, "GEOM::mediasize", sc->mediasize))
225219089Spjd			return;
226219089Spjd		if (g_handleattr_int(bp, "GEOM::sectorsize", sc->sectorsize))
227201143Sdelphij			return;
228185029Spjd		bp2 = g_clone_bio(bp);
229219089Spjd		bp2->bio_done = g_std_done;
230219089Spjd		bp2->bio_offset += sc->sectorsize;
231185029Spjd		g_io_request(bp2, cp);
232219089Spjd		break;
233185029Spjd	default:
234185029Spjd		bp->bio_error = EOPNOTSUPP;
235185029Spjd		g_io_deliver(bp);
236219089Spjd		return;
237185029Spjd	}
238185029Spjd	return;
239185029Spjd}
240219089Spjd
241219089Spjdstatic void
242219089Spjdg_aes_orphan(struct g_consumer *cp)
243168404Spjd{
244185029Spjd	struct g_geom *gp;
245219089Spjd	struct g_provider *pp;
246185029Spjd	struct g_aes_softc *sc;
247219089Spjd	int error;
248185029Spjd
249185029Spjd	g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name);
250219089Spjd	g_topology_assert();
251185029Spjd	KASSERT(cp->provider->error != 0,
252185029Spjd		("g_aes_orphan with error == 0"));
253219089Spjd
254185029Spjd	gp = cp->geom;
255185029Spjd	sc = gp->softc;
256219089Spjd	gp->flags |= G_GEOM_WITHER;
257185029Spjd	error = cp->provider->error;
258185029Spjd	LIST_FOREACH(pp, &gp->provider, provider)
259219089Spjd		g_orphan_provider(pp, error);
260185029Spjd	bzero(sc, sizeof(struct g_aes_softc));	/* destroy evidence */
261219089Spjd	return;
262185029Spjd}
263185029Spjd
264219089Spjdstatic int
265185029Spjdg_aes_access(struct g_provider *pp, int dr, int dw, int de)
266185029Spjd{
267219089Spjd	struct g_geom *gp;
268185029Spjd	struct g_consumer *cp;
269185029Spjd
270168404Spjd	gp = pp->geom;
271185029Spjd	cp = LIST_FIRST(&gp->consumer);
272219089Spjd	/* On first open, grab an extra "exclusive" bit */
273185029Spjd	if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
274228103Smm		de++;
275219089Spjd	/* ... and let go of it on last close */
276185029Spjd	if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
277185029Spjd		de--;
278168404Spjd	return (g_access_rel(cp, dr, dw, de));
279185029Spjd}
280219089Spjd
281185029Spjdstatic struct g_geom *
282219089Spjdg_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
283219089Spjd{
284219089Spjd	struct g_geom *gp;
285185029Spjd	struct g_consumer *cp;
286185029Spjd	struct g_aes_softc *sc;
287219089Spjd	int error;
288185029Spjd	u_int sectorsize;
289185029Spjd	off_t mediasize;
290185029Spjd	u_char *buf;
291219089Spjd
292219089Spjd	g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name);
293219089Spjd	g_topology_assert();
294185029Spjd	gp = g_new_geomf(mp, "%s.aes", pp->name);
295185029Spjd	gp->start = g_aes_start;
296185029Spjd	gp->orphan = g_aes_orphan;
297219089Spjd	gp->spoiled = g_std_spoiled;
298185029Spjd	cp = g_new_consumer(gp);
299185029Spjd	g_attach(cp, pp);
300185029Spjd	error = g_access_rel(cp, 1, 0, 0);
301185029Spjd	if (error) {
302219089Spjd		g_detach(cp);
303185029Spjd		g_destroy_consumer(cp);
304228103Smm		g_destroy_geom(gp);
305228103Smm		return (NULL);
306219089Spjd	}
307219089Spjd	buf = NULL;
308219089Spjd	while (1) {
309219089Spjd		if (gp->rank != 2)
310219089Spjd			break;
311219089Spjd		error = g_getattr("GEOM::sectorsize", cp, &sectorsize);
312219089Spjd		if (error)
313185029Spjd			break;
314219089Spjd		error = g_getattr("GEOM::mediasize", cp, &mediasize);
315219089Spjd		if (error)
316219089Spjd			break;
317219089Spjd		buf = g_read_data(cp, 0, sectorsize, &error);
318219089Spjd		if (buf == NULL || error != 0) {
319219089Spjd			break;
320185029Spjd		}
321185029Spjd		sc = g_malloc(sizeof(struct g_aes_softc), M_WAITOK | M_ZERO);
322219089Spjd		if (!memcmp(buf, aes_magic, strlen(aes_magic))) {
323185029Spjd			sc->keying = KEY_ZERO;
324219089Spjd		} else if (!memcmp(buf, aes_magic_random,
325185029Spjd		    strlen(aes_magic_random))) {
326219089Spjd			sc->keying = KEY_RANDOM;
327219089Spjd		} else if (!memcmp(buf, aes_magic_test,
328219089Spjd		    strlen(aes_magic_test))) {
329185029Spjd			sc->keying = KEY_TEST;
330185029Spjd		} else {
331223623Smm			g_free(sc);
332223623Smm			break;
333223623Smm		}
334219089Spjd		gp->softc = sc;
335219089Spjd		gp->access = g_aes_access;
336185029Spjd		sc->sectorsize = sectorsize;
337219089Spjd		sc->mediasize = mediasize - sectorsize;
338219089Spjd		rijndael_cipherInit(&sc->ci, MODE_CBC, NULL);
339219089Spjd		if (sc->keying == KEY_TEST) {
340219089Spjd			int i;
341219089Spjd			u_char *p;
342219089Spjd
343219089Spjd			p = sc->master_key;
344219089Spjd			for (i = 0; i < sizeof sc->master_key; i ++)
345219089Spjd				*p++ = i;
346219089Spjd		}
347185029Spjd		if (sc->keying == KEY_RANDOM) {
348185029Spjd			int i;
349219089Spjd			u_int32_t u;
350219089Spjd			u_char *p;
351228103Smm
352228103Smm			p = sc->master_key;
353247585Smm			for (i = 0; i < sizeof sc->master_key; i += sizeof u) {
354247585Smm				u = arc4random();
355247585Smm				*p++ = u;
356247585Smm				*p++ = u >> 8;
357185029Spjd				*p++ = u >> 16;
358185029Spjd				*p++ = u >> 24;
359219089Spjd			}
360185029Spjd		}
361219089Spjd		pp = g_new_providerf(gp, gp->name);
362219089Spjd		pp->mediasize = mediasize - sectorsize;
363219089Spjd		g_error_provider(pp, 0);
364219089Spjd		break;
365185029Spjd	}
366219089Spjd	if (buf)
367185029Spjd		g_free(buf);
368219089Spjd	g_access_rel(cp, -1, 0, 0);
369185029Spjd	if (gp->softc != NULL)
370185029Spjd		return (gp);
371185029Spjd	g_detach(cp);
372185029Spjd	g_destroy_consumer(cp);
373219089Spjd	g_destroy_geom(gp);
374219089Spjd	return (NULL);
375185029Spjd}
376185029Spjd
377185029Spjdstatic struct g_class g_aes_class	= {
378219089Spjd	AES_CLASS_NAME,
379192240Skmacy	g_aes_taste,
380219089Spjd	NULL,
381219089Spjd	G_CLASS_INITIALIZER
382219089Spjd};
383185029Spjd
384219089SpjdDECLARE_GEOM_CLASS(g_aes_class, g_aes);
385219089Spjd