geom_aes.c revision 98066
122347Spst/*-
222347Spst * Copyright (c) 2002 Poul-Henning Kamp
329964Sache * Copyright (c) 2002 Networks Associates Technology, Inc.
492906Smarkm * All rights reserved.
522347Spst *
622347Spst * This software was developed for the FreeBSD Project by Poul-Henning Kamp
722347Spst * and NAI Labs, the Security Research Division of Network Associates, Inc.
822347Spst * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
922347Spst * DARPA CHATS research program.
1022347Spst *
1122347Spst * Redistribution and use in source and binary forms, with or without
1222347Spst * modification, are permitted provided that the following conditions
1322347Spst * are met:
1422347Spst * 1. Redistributions of source code must retain the above copyright
1522347Spst *    notice, this list of conditions and the following disclaimer.
1622347Spst * 2. Redistributions in binary form must reproduce the above copyright
1729964Sache *    notice, this list of conditions and the following disclaimer in the
1822347Spst *    documentation and/or other materials provided with the distribution.
1922347Spst * 3. The names of the authors may not be used to endorse or promote
2022347Spst *    products derived from this software without specific prior written
2122347Spst *    permission.
2222347Spst *
2322347Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2422347Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2522347Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26117501Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2722347Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2822347Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2929964Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3029964Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3122347Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3222347Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3322347Spst * SUCH DAMAGE.
3422347Spst *
3522347Spst * $FreeBSD: head/sys/geom/geom_aes.c 98066 2002-06-09 10:57:34Z phk $
3622347Spst *
3722347Spst * This method provides AES encryption with a compiled in key (default
3822347Spst * all zeroes).
3922347Spst *
4022347Spst * XXX: This could probably save a lot of code by pretending to be a slicer.
4122347Spst */
4222347Spst
4322347Spst#include <sys/param.h>
4422347Spst#ifndef _KERNEL
4522347Spst#include <stdio.h>
4622347Spst#include <string.h>
4722347Spst#include <stdlib.h>
4822347Spst#include <signal.h>
4922347Spst#include <err.h>
5022347Spst#else
5122347Spst#include <sys/systm.h>
5222347Spst#include <sys/kernel.h>
5322347Spst#include <sys/conf.h>
5422347Spst#include <sys/bio.h>
5522347Spst#include <sys/malloc.h>
5622347Spst#include <sys/lock.h>
5722347Spst#include <sys/mutex.h>
5822347Spst#endif
5922347Spst#include <sys/errno.h>
6022347Spst#include <geom/geom.h>
6122347Spst
6222347Spst#include <crypto/rijndael/rijndael.h>
6322347Spst
6422347Spst#include <crypto/rijndael/rijndael.h>
6522347Spst
6622347Spst#define AES_CLASS_NAME "AES"
6722347Spst
6822347Spststatic u_char *aes_magic = "<<FreeBSD-GEOM-AES>>";
6922347Spst
7022347Spststatic u_char aes_key[128 / 8] = {
7122347Spst	0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0
7222347Spst};
7322347Spst
7422347Spststruct g_aes_softc {
7522347Spst	u_int	sectorsize;
7622347Spst	off_t	mediasize;
7722347Spst	keyInstance ekey;
7822347Spst	keyInstance dkey;
7922347Spst	cipherInstance ci;
8022347Spst};
8122347Spst
8222347Spststatic void
8322347Spstg_aes_read_done(struct bio *bp)
8422347Spst{
8522347Spst	struct g_geom *gp;
8622347Spst	struct g_aes_softc *sc;
8722347Spst	u_char *p, *b, *e, *sb;
88117501Skris
89117501Skris	gp = bp->bio_from->geom;
90117501Skris	sc = gp->softc;
9122347Spst	sb = g_malloc(sc->sectorsize, M_WAITOK);
9222347Spst	b = bp->bio_data;
9322347Spst	e = bp->bio_data;
9422347Spst	e += bp->bio_length;
9522347Spst	for (p = b; p < e; p += sc->sectorsize) {
9629964Sache		rijndael_blockDecrypt(&sc->ci, &sc->dkey, p, sc->sectorsize * 8, sb);
9722347Spst		bcopy(sb, p, sc->sectorsize);
9822347Spst	}
9922347Spst	g_std_done(bp);
10022347Spst}
10122347Spst
10222347Spststatic void
10329964Sacheg_aes_write_done(struct bio *bp)
10429964Sache{
10522347Spst
10622347Spst	g_free(bp->bio_data);
10729964Sache	g_std_done(bp);
10822347Spst}
10922347Spst
110117501Skrisstatic void
11122347Spstg_aes_start(struct bio *bp)
11222347Spst{
11322347Spst	struct g_geom *gp;
11422347Spst	struct g_consumer *cp;
11522347Spst	struct g_aes_softc *sc;
11622347Spst	struct bio *bp2;
11722347Spst	u_char *p1, *p2, *b, *e;
11822347Spst
119117501Skris	gp = bp->bio_to->geom;
12022347Spst	cp = LIST_FIRST(&gp->consumer);
12122347Spst	sc = gp->softc;
122117501Skris	switch (bp->bio_cmd) {
123117501Skris	case BIO_READ:
12422347Spst		bp2 = g_clone_bio(bp);
12522347Spst		bp2->bio_done = g_aes_read_done;
12622347Spst		bp2->bio_offset += sc->sectorsize;
127117501Skris		g_io_request(bp2, cp);
12822347Spst		break;
12922347Spst	case BIO_WRITE:
13022347Spst		bp2 = g_clone_bio(bp);
13122347Spst		bp2->bio_done = g_aes_write_done;
13222347Spst		bp2->bio_offset += sc->sectorsize;
13322347Spst		bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK);
13422347Spst		b = bp->bio_data;
135117501Skris		e = bp->bio_data;
13622347Spst		e += bp->bio_length;
13722347Spst		p2 = bp2->bio_data;
13822347Spst		for (p1 = b; p1 < e; p1 += sc->sectorsize) {
13922347Spst			rijndael_blockEncrypt(&sc->ci, &sc->ekey,
14022347Spst			    p1, sc->sectorsize * 8, p2);
14122347Spst			p2 += sc->sectorsize;
14222347Spst		}
14322347Spst		g_io_request(bp2, cp);
14422347Spst		break;
14522347Spst	case BIO_GETATTR:
14622347Spst	case BIO_SETATTR:
14722347Spst		if (g_handleattr_off_t(bp, "GEOM::mediasize", sc->mediasize))
14822347Spst			return;
14922347Spst		if (g_handleattr_int(bp, "GEOM::sectorsize", sc->sectorsize))
15022347Spst			return;
15122347Spst		bp2 = g_clone_bio(bp);
15222347Spst		bp2->bio_done = g_std_done;
15322347Spst		bp2->bio_offset += sc->sectorsize;
15422347Spst		g_io_request(bp2, cp);
15522347Spst		break;
15622347Spst	default:
15722347Spst		bp->bio_error = EOPNOTSUPP;
15822347Spst		g_io_deliver(bp);
15922347Spst		return;
16022347Spst	}
16122347Spst	return;
16229964Sache}
16322347Spst
16422347Spststatic void
16522347Spstg_aes_orphan(struct g_consumer *cp)
16622347Spst{
16722347Spst	struct g_geom *gp;
16822347Spst	struct g_provider *pp;
16922347Spst	int error;
17022347Spst
17122347Spst	g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name);
17222347Spst	g_topology_assert();
17322347Spst	KASSERT(cp->provider->error != 0,
17422347Spst		("g_aes_orphan with error == 0"));
17522347Spst
17622347Spst	gp = cp->geom;
17722347Spst	gp->flags |= G_GEOM_WITHER;
17822347Spst	error = cp->provider->error;
17922347Spst	LIST_FOREACH(pp, &gp->provider, provider)
18022347Spst		g_orphan_provider(pp, error);
18122347Spst	return;
18222347Spst}
18322347Spst
18422347Spststatic int
18522347Spstg_aes_access(struct g_provider *pp, int dr, int dw, int de)
18622347Spst{
18722347Spst	struct g_geom *gp;
18822347Spst	struct g_consumer *cp;
18922347Spst
19022347Spst	gp = pp->geom;
19122347Spst	cp = LIST_FIRST(&gp->consumer);
19222347Spst	/* On first open, grab an extra "exclusive" bit */
19322347Spst	if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
19422347Spst		de++;
19522347Spst	/* ... and let go of it on last close */
19622347Spst	if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
19722347Spst		de--;
19822347Spst	return (g_access_rel(cp, dr, dw, de));
19922347Spst}
20022347Spst
20122347Spststatic struct g_geom *
20222347Spstg_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
20322347Spst{
20422347Spst	struct g_geom *gp;
20522347Spst	struct g_consumer *cp;
20622347Spst	struct g_aes_softc *sc;
20722347Spst	int error;
20829964Sache	u_int sectorsize;
20929964Sache	off_t mediasize;
21029964Sache	u_char *buf;
21129964Sache
21229964Sache	g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name);
21329964Sache	g_topology_assert();
21422347Spst	gp = g_new_geomf(mp, "%s.aes", pp->name);
21529964Sache	gp->start = g_aes_start;
21622347Spst	gp->orphan = g_aes_orphan;
217	gp->spoiled = g_std_spoiled;
218	cp = g_new_consumer(gp);
219	g_attach(cp, pp);
220	error = g_access_rel(cp, 1, 0, 0);
221	if (error) {
222		g_detach(cp);
223		g_destroy_consumer(cp);
224		g_destroy_geom(gp);
225		return (NULL);
226	}
227	buf = NULL;
228	while (1) {
229		if (gp->rank != 2)
230			break;
231		error = g_getattr("GEOM::sectorsize", cp, &sectorsize);
232		if (error)
233			break;
234		error = g_getattr("GEOM::mediasize", cp, &mediasize);
235		if (error)
236			break;
237		buf = g_read_data(cp, 0, sectorsize, &error);
238		if (buf == NULL || error != 0) {
239			break;
240		}
241		if (memcmp(buf, aes_magic, strlen(aes_magic)))
242			break;
243		sc = g_malloc(sizeof(struct g_aes_softc), M_WAITOK | M_ZERO);
244		gp->softc = sc;
245		gp->access = g_aes_access;
246		sc->sectorsize = sectorsize;
247		sc->mediasize = mediasize - sectorsize;
248		rijndael_cipherInit(&sc->ci, MODE_CBC, NULL);
249		rijndael_makeKey(&sc->ekey, DIR_ENCRYPT, 128, aes_key);
250		rijndael_makeKey(&sc->dkey, DIR_DECRYPT, 128, aes_key);
251		pp = g_new_providerf(gp, gp->name);
252		pp->mediasize = mediasize - sectorsize;
253		g_error_provider(pp, 0);
254		break;
255	}
256	if (buf)
257		g_free(buf);
258	g_access_rel(cp, -1, 0, 0);
259	if (gp->softc != NULL)
260		return (gp);
261	g_detach(cp);
262	g_destroy_consumer(cp);
263	g_destroy_geom(gp);
264	return (NULL);
265}
266
267static struct g_class g_aes_class	= {
268	AES_CLASS_NAME,
269	g_aes_taste,
270	NULL,
271	G_CLASS_INITIALIZER
272};
273
274DECLARE_GEOM_CLASS(g_aes_class, g_aes);
275