geom_aes.c revision 97318
197318Sphk/*- 297318Sphk * Copyright (c) 2002 Poul-Henning Kamp 397318Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 497318Sphk * All rights reserved. 597318Sphk * 697318Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 797318Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 897318Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 997318Sphk * DARPA CHATS research program. 1097318Sphk * 1197318Sphk * Redistribution and use in source and binary forms, with or without 1297318Sphk * modification, are permitted provided that the following conditions 1397318Sphk * are met: 1497318Sphk * 1. Redistributions of source code must retain the above copyright 1597318Sphk * notice, this list of conditions and the following disclaimer. 1697318Sphk * 2. Redistributions in binary form must reproduce the above copyright 1797318Sphk * notice, this list of conditions and the following disclaimer in the 1897318Sphk * documentation and/or other materials provided with the distribution. 1997318Sphk * 3. The names of the authors may not be used to endorse or promote 2097318Sphk * products derived from this software without specific prior written 2197318Sphk * permission. 2297318Sphk * 2397318Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2497318Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2597318Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2697318Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2797318Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2897318Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2997318Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3097318Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3197318Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3297318Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3397318Sphk * SUCH DAMAGE. 3497318Sphk * 3597318Sphk * $FreeBSD: head/sys/geom/geom_aes.c 97318 2002-05-26 18:14:38Z phk $ 3697318Sphk * 3797318Sphk * This method provides AES encryption with a compiled in key (default 3897318Sphk * all zeroes). 3997318Sphk * 4097318Sphk * XXX: This could probably save a lot of code by pretending to be a slicer. 4197318Sphk */ 4297318Sphk 4397318Sphk#include <sys/param.h> 4497318Sphk#ifndef _KERNEL 4597318Sphk#include <stdio.h> 4697318Sphk#include <string.h> 4797318Sphk#include <stdlib.h> 4897318Sphk#include <signal.h> 4997318Sphk#include <err.h> 5097318Sphk#else 5197318Sphk#include <sys/systm.h> 5297318Sphk#include <sys/kernel.h> 5397318Sphk#include <sys/conf.h> 5497318Sphk#include <sys/bio.h> 5597318Sphk#include <sys/malloc.h> 5697318Sphk#include <sys/lock.h> 5797318Sphk#include <sys/mutex.h> 5897318Sphk#endif 5997318Sphk#include <sys/errno.h> 6097318Sphk#include <geom/geom.h> 6197318Sphk 6297318Sphk#include <crypto/rijndael/rijndael.h> 6397318Sphk 6497318Sphk#include <crypto/rijndael/rijndael.h> 6597318Sphk 6697318Sphk#define AES_CLASS_NAME "AES" 6797318Sphk 6897318Sphkstatic u_char *aes_magic = "<<FreeBSD-GEOM-AES>>"; 6997318Sphk 7097318Sphkstatic u_char aes_key[128 / 8] = { 7197318Sphk 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 7297318Sphk}; 7397318Sphk 7497318Sphkstruct g_aes_softc { 7597318Sphk u_int sectorsize; 7697318Sphk off_t mediasize; 7797318Sphk keyInstance ekey; 7897318Sphk keyInstance dkey; 7997318Sphk cipherInstance ci; 8097318Sphk}; 8197318Sphk 8297318Sphkstatic void 8397318Sphkg_aes_read_done(struct bio *bp) 8497318Sphk{ 8597318Sphk struct g_geom *gp; 8697318Sphk struct g_aes_softc *sc; 8797318Sphk u_char *p, *b, *e, *sb; 8897318Sphk 8997318Sphk gp = bp->bio_from->geom; 9097318Sphk sc = gp->softc; 9197318Sphk sb = g_malloc(sc->sectorsize, M_WAITOK); 9297318Sphk b = bp->bio_data; 9397318Sphk e = bp->bio_data; 9497318Sphk e += bp->bio_length; 9597318Sphk for (p = b; p < e; p += sc->sectorsize) { 9697318Sphk rijndael_blockDecrypt(&sc->ci, &sc->dkey, p, sc->sectorsize * 8, sb); 9797318Sphk bcopy(sb, p, sc->sectorsize); 9897318Sphk } 9997318Sphk g_std_done(bp); 10097318Sphk} 10197318Sphk 10297318Sphkstatic void 10397318Sphkg_aes_write_done(struct bio *bp) 10497318Sphk{ 10597318Sphk 10697318Sphk g_free(bp->bio_data); 10797318Sphk g_std_done(bp); 10897318Sphk} 10997318Sphk 11097318Sphkstatic void 11197318Sphkg_aes_start(struct bio *bp) 11297318Sphk{ 11397318Sphk struct g_geom *gp; 11497318Sphk struct g_consumer *cp; 11597318Sphk struct g_aes_softc *sc; 11697318Sphk struct bio *bp2; 11797318Sphk u_char *p1, *p2, *b, *e; 11897318Sphk 11997318Sphk gp = bp->bio_to->geom; 12097318Sphk cp = LIST_FIRST(&gp->consumer); 12197318Sphk sc = gp->softc; 12297318Sphk switch (bp->bio_cmd) { 12397318Sphk case BIO_READ: 12497318Sphk bp2 = g_clone_bio(bp); 12597318Sphk bp2->bio_done = g_aes_read_done; 12697318Sphk bp2->bio_offset += sc->sectorsize; 12797318Sphk g_io_request(bp2, cp); 12897318Sphk break; 12997318Sphk case BIO_WRITE: 13097318Sphk bp2 = g_clone_bio(bp); 13197318Sphk bp2->bio_done = g_aes_write_done; 13297318Sphk bp2->bio_offset += sc->sectorsize; 13397318Sphk bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK); 13497318Sphk b = bp->bio_data; 13597318Sphk e = bp->bio_data; 13697318Sphk e += bp->bio_length; 13797318Sphk p2 = bp2->bio_data; 13897318Sphk for (p1 = b; p1 < e; p1 += sc->sectorsize) { 13997318Sphk rijndael_blockEncrypt(&sc->ci, &sc->ekey, 14097318Sphk p1, sc->sectorsize * 8, p2); 14197318Sphk p2 += sc->sectorsize; 14297318Sphk } 14397318Sphk g_io_request(bp2, cp); 14497318Sphk break; 14597318Sphk case BIO_GETATTR: 14697318Sphk case BIO_SETATTR: 14797318Sphk if (g_haveattr_off_t(bp, "GEOM::mediasize", sc->mediasize)) 14897318Sphk return; 14997318Sphk if (g_haveattr_int(bp, "GEOM::sectorsize", sc->sectorsize)) 15097318Sphk return; 15197318Sphk bp2 = g_clone_bio(bp); 15297318Sphk bp2->bio_done = g_std_done; 15397318Sphk bp2->bio_offset += sc->sectorsize; 15497318Sphk g_io_request(bp2, cp); 15597318Sphk break; 15697318Sphk default: 15797318Sphk bp->bio_error = EOPNOTSUPP; 15897318Sphk g_io_deliver(bp); 15997318Sphk return; 16097318Sphk } 16197318Sphk return; 16297318Sphk} 16397318Sphk 16497318Sphkstatic void 16597318Sphkg_aes_orphan(struct g_consumer *cp) 16697318Sphk{ 16797318Sphk struct g_geom *gp; 16897318Sphk struct g_provider *pp; 16997318Sphk int error; 17097318Sphk 17197318Sphk g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name); 17297318Sphk g_topology_assert(); 17397318Sphk KASSERT(cp->provider->error != 0, 17497318Sphk ("g_aes_orphan with error == 0")); 17597318Sphk 17697318Sphk gp = cp->geom; 17797318Sphk gp->flags |= G_GEOM_WITHER; 17897318Sphk error = cp->provider->error; 17997318Sphk LIST_FOREACH(pp, &gp->provider, provider) 18097318Sphk g_orphan_provider(pp, error); 18197318Sphk return; 18297318Sphk} 18397318Sphk 18497318Sphkstatic int 18597318Sphkg_aes_access(struct g_provider *pp, int dr, int dw, int de) 18697318Sphk{ 18797318Sphk struct g_geom *gp; 18897318Sphk struct g_consumer *cp; 18997318Sphk 19097318Sphk gp = pp->geom; 19197318Sphk cp = LIST_FIRST(&gp->consumer); 19297318Sphk /* On first open, grab an extra "exclusive" bit */ 19397318Sphk if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) 19497318Sphk de++; 19597318Sphk /* ... and let go of it on last close */ 19697318Sphk if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) 19797318Sphk de--; 19897318Sphk return (g_access_rel(cp, dr, dw, de)); 19997318Sphk} 20097318Sphk 20197318Sphkstatic struct g_geom * 20297318Sphkg_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 20397318Sphk{ 20497318Sphk struct g_geom *gp; 20597318Sphk struct g_consumer *cp; 20697318Sphk struct g_aes_softc *sc; 20797318Sphk int error; 20897318Sphk u_int sectorsize; 20997318Sphk off_t mediasize; 21097318Sphk u_char *buf; 21197318Sphk 21297318Sphk g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name); 21397318Sphk g_topology_assert(); 21497318Sphk gp = g_new_geomf(mp, "%s.aes", pp->name); 21597318Sphk gp->start = g_aes_start; 21697318Sphk gp->orphan = g_aes_orphan; 21797318Sphk gp->spoiled = g_std_spoiled; 21897318Sphk cp = g_new_consumer(gp); 21997318Sphk g_attach(cp, pp); 22097318Sphk error = g_access_rel(cp, 1, 0, 0); 22197318Sphk if (error) { 22297318Sphk g_dettach(cp); 22397318Sphk g_destroy_consumer(cp); 22497318Sphk g_destroy_geom(gp); 22597318Sphk return (NULL); 22697318Sphk } 22797318Sphk buf = NULL; 22897318Sphk while (1) { 22997318Sphk if (gp->rank != 2) 23097318Sphk break; 23197318Sphk error = g_getattr("GEOM::sectorsize", cp, §orsize); 23297318Sphk if (error) 23397318Sphk break; 23497318Sphk error = g_getattr("GEOM::mediasize", cp, &mediasize); 23597318Sphk if (error) 23697318Sphk break; 23797318Sphk buf = g_read_data(cp, 0, sectorsize, &error); 23897318Sphk if (buf == NULL || error != 0) { 23997318Sphk break; 24097318Sphk } 24197318Sphk if (memcmp(buf, aes_magic, strlen(aes_magic))) 24297318Sphk break; 24397318Sphk sc = g_malloc(sizeof(struct g_aes_softc), M_WAITOK | M_ZERO); 24497318Sphk gp->softc = sc; 24597318Sphk gp->access = g_aes_access; 24697318Sphk sc->sectorsize = sectorsize; 24797318Sphk sc->mediasize = mediasize - sectorsize; 24897318Sphk rijndael_cipherInit(&sc->ci, MODE_CBC, NULL); 24997318Sphk rijndael_makeKey(&sc->ekey, DIR_ENCRYPT, 128, aes_key); 25097318Sphk rijndael_makeKey(&sc->dkey, DIR_DECRYPT, 128, aes_key); 25197318Sphk pp = g_new_providerf(gp, gp->name); 25297318Sphk pp->mediasize = mediasize - sectorsize; 25397318Sphk g_error_provider(pp, 0); 25497318Sphk break; 25597318Sphk } 25697318Sphk if (buf) 25797318Sphk g_free(buf); 25897318Sphk g_access_rel(cp, -1, 0, 0); 25997318Sphk if (gp->softc != NULL) 26097318Sphk return (gp); 26197318Sphk g_dettach(cp); 26297318Sphk g_destroy_consumer(cp); 26397318Sphk g_destroy_geom(gp); 26497318Sphk return (NULL); 26597318Sphk} 26697318Sphk 26797318Sphkstatic struct g_class g_aes_class = { 26897318Sphk AES_CLASS_NAME, 26997318Sphk g_aes_taste, 27097318Sphk NULL, 27197318Sphk G_CLASS_INITSTUFF 27297318Sphk}; 27397318Sphk 27497318SphkDECLARE_GEOM_CLASS(g_aes_class, g_aes); 275