geom_aes.c revision 114736
171579Sdeischen/*-
271579Sdeischen * Copyright (c) 2002 Poul-Henning Kamp
371579Sdeischen * Copyright (c) 2002 Networks Associates Technology, Inc.
471579Sdeischen * All rights reserved.
571579Sdeischen *
671579Sdeischen * This software was developed for the FreeBSD Project by Poul-Henning Kamp
771579Sdeischen * and NAI Labs, the Security Research Division of Network Associates, Inc.
871579Sdeischen * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
971579Sdeischen * DARPA CHATS research program.
1071579Sdeischen *
1171579Sdeischen * Redistribution and use in source and binary forms, with or without
1271579Sdeischen * modification, are permitted provided that the following conditions
1371579Sdeischen * are met:
1471579Sdeischen * 1. Redistributions of source code must retain the above copyright
1571579Sdeischen *    notice, this list of conditions and the following disclaimer.
1671579Sdeischen * 2. Redistributions in binary form must reproduce the above copyright
1771579Sdeischen *    notice, this list of conditions and the following disclaimer in the
1871579Sdeischen *    documentation and/or other materials provided with the distribution.
1971579Sdeischen * 3. The names of the authors may not be used to endorse or promote
2071579Sdeischen *    products derived from this software without specific prior written
2171579Sdeischen *    permission.
2271579Sdeischen *
2371579Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2471579Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2571579Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2671579Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2771579Sdeischen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2871579Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2971579Sdeischen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3071579Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3171579Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3271579Sdeischen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3382496Sbde * SUCH DAMAGE.
34106866Sdeischen *
35106866Sdeischen * $FreeBSD: head/sys/geom/geom_aes.c 114736 2003-05-05 15:52:11Z phk $
36106866Sdeischen *
3782496Sbde * This method provides AES encryption with a compiled in key (default
3882496Sbde * all zeroes).
3982496Sbde *
4082496Sbde * XXX: This could probably save a lot of code by pretending to be a slicer.
4182496Sbde */
4282496Sbde
4386250Sbde#include <sys/param.h>
4482496Sbde#include <sys/systm.h>
45113595Snectar#include <sys/kernel.h>
4682496Sbde#include <sys/conf.h>
4782496Sbde#include <sys/bio.h>
4871579Sdeischen#include <sys/malloc.h>
4971579Sdeischen#include <sys/lock.h>
5071579Sdeischen#include <sys/mutex.h>
5171579Sdeischen#include <sys/libkern.h>
5275186Stmm#include <sys/endian.h>
5375186Stmm#include <sys/md5.h>
5475186Stmm#include <sys/errno.h>
5575186Stmm#include <geom/geom.h>
5671579Sdeischen
5775186Stmm#include <crypto/rijndael/rijndael.h>
5875186Stmm
5971579Sdeischen#include <crypto/rijndael/rijndael.h>
6071579Sdeischen
6171579Sdeischen#define AES_CLASS_NAME "AES"
6271579Sdeischen
6371579Sdeischen#define MASTER_KEY_LENGTH	(1024/8)
6471579Sdeischen
6571579Sdeischenstatic const u_char *aes_magic = "<<FreeBSD-GEOM-AES>>";
6671579Sdeischenstatic const u_char *aes_magic_random = "<<FreeBSD-GEOM-AES-RANDOM>>";
67111010Snectarstatic const u_char *aes_magic_test = "<<FreeBSD-GEOM-AES-TEST>>";
6871579Sdeischen
6971579Sdeischen
7071579Sdeischenstruct g_aes_softc {
7171579Sdeischen	enum {
7271579Sdeischen		KEY_ZERO,
7371579Sdeischen		KEY_RANDOM,
7471579Sdeischen		KEY_TEST
7593399Smarkm	} keying;
7671579Sdeischen	u_int	sectorsize;
7771579Sdeischen	off_t	mediasize;
7871579Sdeischen	cipherInstance ci;
7971579Sdeischen	u_char master_key[MASTER_KEY_LENGTH];
8071579Sdeischen};
8171579Sdeischen
8271579Sdeischen/*
83197968Sjilles * Generate a sectorkey from the masterkey and the offset position.
8474462Salfred *
85156319Sdeischen * For KEY_ZERO we just return a key of all zeros.
86156319Sdeischen *
87157218Sdes * We feed the sector byte offset, 16 bytes of the master-key and
88177607Sru * the sector byte offset once more to MD5.
89156319Sdeischen * The sector byte offset is converted to little-endian format first
90156319Sdeischen * to support multi-architecture operation.
91156319Sdeischen * We use 16 bytes from the master-key starting at the logical sector
92156319Sdeischen * number modulus he length of the master-key.  If need be we wrap
93156319Sdeischen * around to the start of the master-key.
94156319Sdeischen */
95157218Sdes
96157218Sdesstatic void
97157218Sdesg_aes_makekey(struct g_aes_softc *sc, off_t off, keyInstance *ki, int dir)
98156319Sdeischen{
99177607Sru	MD5_CTX cx;
100157218Sdes	u_int64_t u64;
101156319Sdeischen	u_int u, u1;
102156319Sdeischen	u_char *p, buf[16];
103156319Sdeischen
104156319Sdeischen	if (sc->keying == KEY_ZERO) {
105156319Sdeischen		rijndael_makeKey(ki, dir, 128, sc->master_key);
106156319Sdeischen		return;
107157218Sdes	}
108157218Sdes	MD5Init(&cx);
109157218Sdes	u64 = htole64(off);
110157218Sdes	MD5Update(&cx, (u_char *)&u64, sizeof(u64));
111157218Sdes	u = off / sc->sectorsize;
112157218Sdes	u %= sizeof sc->master_key;
113157218Sdes	p = sc->master_key + u;
114157218Sdes	if (u + 16 <= sizeof(sc->master_key)) {
115157218Sdes		MD5Update(&cx, p, 16);
116157218Sdes	} else {
117156319Sdeischen		u1 = sizeof sc->master_key - u;
118106866Sdeischen		MD5Update(&cx, p, u1);
119106866Sdeischen		MD5Update(&cx, sc->master_key, 16 - u1);
120106866Sdeischen		u1 = 0;				/* destroy evidence */
12174462Salfred	}
122106866Sdeischen	u = 0;					/* destroy evidence */
12374462Salfred	MD5Update(&cx, (u_char *)&u64, sizeof(u64));
124157218Sdes	u64 = 0;				/* destroy evidence */
125157218Sdes	MD5Final(buf, &cx);
126157218Sdes	bzero(&cx, sizeof cx);			/* destroy evidence */
127157218Sdes	rijndael_makeKey(ki, dir, 128, buf);
128157218Sdes	bzero(buf, sizeof buf);			/* destroy evidence */
129157218Sdes
130157218Sdes}
131156319Sdeischen
132156319Sdeischenstatic void
13374462Salfredg_aes_read_done(struct bio *bp)
134177855Sdavidxu{
135157218Sdes	struct g_geom *gp;
136177607Sru	struct g_aes_softc *sc;
137157218Sdes	u_char *p, *b, *e, *sb;
138157218Sdes	keyInstance dkey;
13971579Sdeischen	off_t o;
140218414Sjkim
141156319Sdeischen	gp = bp->bio_from->geom;
14271579Sdeischen	sc = gp->softc;
14371579Sdeischen	sb = g_malloc(sc->sectorsize, M_WAITOK);
144157218Sdes	b = bp->bio_data;
14574462Salfred	e = bp->bio_data;
146157218Sdes	e += bp->bio_length;
14771579Sdeischen	o = bp->bio_offset - sc->sectorsize;
148157218Sdes	for (p = b; p < e; p += sc->sectorsize) {
14971579Sdeischen		g_aes_makekey(sc, o, &dkey, DIR_DECRYPT);
150176058Sdes		rijndael_blockDecrypt(&sc->ci, &dkey, p, sc->sectorsize * 8, sb);
15171579Sdeischen		bcopy(sb, p, sc->sectorsize);
152157218Sdes		o += sc->sectorsize;
153157218Sdes	}
15471579Sdeischen	bzero(&dkey, sizeof dkey);		/* destroy evidence */
15571579Sdeischen	bzero(sb, sc->sectorsize);		/* destroy evidence */
156106866Sdeischen	g_free(sb);
157157218Sdes	g_std_done(bp);
158157218Sdes}
159157218Sdes
160157218Sdesstatic void
161157218Sdesg_aes_write_done(struct bio *bp)
16271579Sdeischen{
163157218Sdes	struct g_aes_softc *sc;
164157218Sdes	struct g_geom *gp;
165157218Sdes
166157218Sdes	gp = bp->bio_to->geom;
16771579Sdeischen	sc = gp->softc;
16871579Sdeischen	bzero(bp->bio_data, bp->bio_length);	/* destroy evidence */
169157218Sdes	g_free(bp->bio_data);
170157218Sdes	g_std_done(bp);
171106866Sdeischen}
17274462Salfred
17374462Salfredstatic void
174157218Sdesg_aes_start(struct bio *bp)
175157218Sdes{
176106866Sdeischen	struct g_geom *gp;
177106866Sdeischen	struct g_consumer *cp;
17874462Salfred	struct g_aes_softc *sc;
179157218Sdes	struct bio *bp2;
180157218Sdes	u_char *p1, *p2, *b, *e;
181157218Sdes	keyInstance ekey;
182157218Sdes	off_t o;
183157218Sdes
18472373Sdeischen	gp = bp->bio_to->geom;
185157218Sdes	cp = LIST_FIRST(&gp->consumer);
186177855Sdavidxu	sc = gp->softc;
187156319Sdeischen	switch (bp->bio_cmd) {
188156319Sdeischen	case BIO_READ:
189157218Sdes		bp2 = g_clone_bio(bp);
190157218Sdes		if (bp2 == NULL) {
191157218Sdes			g_io_deliver(bp, ENOMEM);
19271579Sdeischen			return;
19374462Salfred		}
194157218Sdes		bp2->bio_done = g_aes_read_done;
195157218Sdes		bp2->bio_offset += sc->sectorsize;
196157218Sdes		g_io_request(bp2, cp);
197157218Sdes		break;
198157218Sdes	case BIO_WRITE:
199157218Sdes		bp2 = g_clone_bio(bp);
200157218Sdes		if (bp2 == NULL) {
201157218Sdes			g_io_deliver(bp, ENOMEM);
202157218Sdes			return;
203157218Sdes		}
204156319Sdeischen		bp2->bio_done = g_aes_write_done;
205157218Sdes		bp2->bio_offset += sc->sectorsize;
206157218Sdes		bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK);
20771579Sdeischen		b = bp->bio_data;
20871579Sdeischen		e = bp->bio_data;
20971579Sdeischen		e += bp->bio_length;
21071579Sdeischen		p2 = bp2->bio_data;
21171579Sdeischen		o = bp->bio_offset;
212157223Sdes		for (p1 = b; p1 < e; p1 += sc->sectorsize) {
213157223Sdes			g_aes_makekey(sc, o, &ekey, DIR_ENCRYPT);
214157223Sdes			rijndael_blockEncrypt(&sc->ci, &ekey,
215157223Sdes			    p1, sc->sectorsize * 8, p2);
216157223Sdes			p2 += sc->sectorsize;
217157223Sdes			o += sc->sectorsize;
218157223Sdes		}
219157223Sdes		bzero(&ekey, sizeof ekey);	/* destroy evidence */
220157223Sdes		g_io_request(bp2, cp);
221157223Sdes		break;
22271579Sdeischen	case BIO_GETATTR:
22371579Sdeischen		bp2 = g_clone_bio(bp);
22471579Sdeischen		if (bp2 == NULL) {
22571579Sdeischen			g_io_deliver(bp, ENOMEM);
22671579Sdeischen			return;
22771579Sdeischen		}
22871579Sdeischen		bp2->bio_done = g_std_done;
22971579Sdeischen		bp2->bio_offset += sc->sectorsize;
230148655Sdeischen		g_io_request(bp2, cp);
23171579Sdeischen		break;
232242960Skib	default:
233108864Stjr		g_io_deliver(bp, EOPNOTSUPP);
23471579Sdeischen		return;
23571579Sdeischen	}
23671579Sdeischen	return;
23771579Sdeischen}
23871579Sdeischen
23971579Sdeischenstatic void
24071579Sdeischeng_aes_orphan(struct g_consumer *cp)
24171579Sdeischen{
24271579Sdeischen	struct g_geom *gp;
24371579Sdeischen	struct g_aes_softc *sc;
24471579Sdeischen
24571579Sdeischen	g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name);
24671579Sdeischen	g_topology_assert();
24771579Sdeischen	KASSERT(cp->provider->error != 0,
24871579Sdeischen		("g_aes_orphan with error == 0"));
24971579Sdeischen
25071579Sdeischen	gp = cp->geom;
25171579Sdeischen	sc = gp->softc;
25271579Sdeischen	g_wither_geom(gp, cp->provider->error);
25371579Sdeischen	bzero(sc, sizeof(struct g_aes_softc));	/* destroy evidence */
25471579Sdeischen	g_free(sc);
25571579Sdeischen	return;
25671579Sdeischen}
25771579Sdeischen
25871579Sdeischenstatic int
25971579Sdeischeng_aes_access(struct g_provider *pp, int dr, int dw, int de)
26071579Sdeischen{
26171579Sdeischen	struct g_geom *gp;
26271579Sdeischen	struct g_consumer *cp;
26371579Sdeischen
26471579Sdeischen	gp = pp->geom;
26571579Sdeischen	cp = LIST_FIRST(&gp->consumer);
26671579Sdeischen	/* On first open, grab an extra "exclusive" bit */
267	if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
268		de++;
269	/* ... and let go of it on last close */
270	if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
271		de--;
272	return (g_access_rel(cp, dr, dw, de));
273}
274
275static struct g_geom *
276g_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
277{
278	struct g_geom *gp;
279	struct g_consumer *cp;
280	struct g_aes_softc *sc;
281	int error;
282	u_int sectorsize;
283	off_t mediasize;
284	u_char *buf;
285
286	g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name);
287	g_topology_assert();
288	gp = g_new_geomf(mp, "%s.aes", pp->name);
289	gp->start = g_aes_start;
290	gp->orphan = g_aes_orphan;
291	gp->spoiled = g_std_spoiled;
292	cp = g_new_consumer(gp);
293	g_attach(cp, pp);
294	error = g_access_rel(cp, 1, 0, 0);
295	if (error) {
296		g_detach(cp);
297		g_destroy_consumer(cp);
298		g_destroy_geom(gp);
299		return (NULL);
300	}
301	buf = NULL;
302	g_topology_unlock();
303	do {
304		if (gp->rank != 2)
305			break;
306		sectorsize = cp->provider->sectorsize;
307		mediasize = cp->provider->mediasize;
308		buf = g_read_data(cp, 0, sectorsize, &error);
309		if (buf == NULL || error != 0) {
310			break;
311		}
312		sc = g_malloc(sizeof(struct g_aes_softc), M_WAITOK | M_ZERO);
313		if (!memcmp(buf, aes_magic, strlen(aes_magic))) {
314			sc->keying = KEY_ZERO;
315		} else if (!memcmp(buf, aes_magic_random,
316		    strlen(aes_magic_random))) {
317			sc->keying = KEY_RANDOM;
318		} else if (!memcmp(buf, aes_magic_test,
319		    strlen(aes_magic_test))) {
320			sc->keying = KEY_TEST;
321		} else {
322			g_free(sc);
323			break;
324		}
325		g_free(buf);
326		gp->softc = sc;
327		gp->access = g_aes_access;
328		sc->sectorsize = sectorsize;
329		sc->mediasize = mediasize - sectorsize;
330		rijndael_cipherInit(&sc->ci, MODE_CBC, NULL);
331		if (sc->keying == KEY_TEST) {
332			int i;
333			u_char *p;
334
335			p = sc->master_key;
336			for (i = 0; i < (int)sizeof sc->master_key; i ++)
337				*p++ = i;
338		}
339		if (sc->keying == KEY_RANDOM) {
340			int i;
341			u_int32_t u;
342			u_char *p;
343
344			p = sc->master_key;
345			for (i = 0; i < (int)sizeof sc->master_key; i += sizeof u) {
346				u = arc4random();
347				*p++ = u;
348				*p++ = u >> 8;
349				*p++ = u >> 16;
350				*p++ = u >> 24;
351			}
352		}
353		g_topology_lock();
354		pp = g_new_providerf(gp, gp->name);
355		pp->mediasize = mediasize - sectorsize;
356		pp->sectorsize = sectorsize;
357		g_error_provider(pp, 0);
358		g_topology_unlock();
359	} while(0);
360	g_topology_lock();
361	if (buf)
362		g_free(buf);
363	g_access_rel(cp, -1, 0, 0);
364	if (gp->softc != NULL)
365		return (gp);
366	g_detach(cp);
367	g_destroy_consumer(cp);
368	g_destroy_geom(gp);
369	return (NULL);
370}
371
372static struct g_class g_aes_class	= {
373	.name = AES_CLASS_NAME,
374	.taste = g_aes_taste,
375	G_CLASS_INITIALIZER
376};
377
378DECLARE_GEOM_CLASS(g_aes_class, g_aes);
379