geom_aes.c revision 97318
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/geom/geom_aes.c 97318 2002-05-26 18:14:38Z phk $ 36 * 37 * This method provides AES encryption with a compiled in key (default 38 * all zeroes). 39 * 40 * XXX: This could probably save a lot of code by pretending to be a slicer. 41 */ 42 43#include <sys/param.h> 44#ifndef _KERNEL 45#include <stdio.h> 46#include <string.h> 47#include <stdlib.h> 48#include <signal.h> 49#include <err.h> 50#else 51#include <sys/systm.h> 52#include <sys/kernel.h> 53#include <sys/conf.h> 54#include <sys/bio.h> 55#include <sys/malloc.h> 56#include <sys/lock.h> 57#include <sys/mutex.h> 58#endif 59#include <sys/errno.h> 60#include <geom/geom.h> 61 62#include <crypto/rijndael/rijndael.h> 63 64#include <crypto/rijndael/rijndael.h> 65 66#define AES_CLASS_NAME "AES" 67 68static u_char *aes_magic = "<<FreeBSD-GEOM-AES>>"; 69 70static u_char aes_key[128 / 8] = { 71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 72}; 73 74struct g_aes_softc { 75 u_int sectorsize; 76 off_t mediasize; 77 keyInstance ekey; 78 keyInstance dkey; 79 cipherInstance ci; 80}; 81 82static void 83g_aes_read_done(struct bio *bp) 84{ 85 struct g_geom *gp; 86 struct g_aes_softc *sc; 87 u_char *p, *b, *e, *sb; 88 89 gp = bp->bio_from->geom; 90 sc = gp->softc; 91 sb = g_malloc(sc->sectorsize, M_WAITOK); 92 b = bp->bio_data; 93 e = bp->bio_data; 94 e += bp->bio_length; 95 for (p = b; p < e; p += sc->sectorsize) { 96 rijndael_blockDecrypt(&sc->ci, &sc->dkey, p, sc->sectorsize * 8, sb); 97 bcopy(sb, p, sc->sectorsize); 98 } 99 g_std_done(bp); 100} 101 102static void 103g_aes_write_done(struct bio *bp) 104{ 105 106 g_free(bp->bio_data); 107 g_std_done(bp); 108} 109 110static void 111g_aes_start(struct bio *bp) 112{ 113 struct g_geom *gp; 114 struct g_consumer *cp; 115 struct g_aes_softc *sc; 116 struct bio *bp2; 117 u_char *p1, *p2, *b, *e; 118 119 gp = bp->bio_to->geom; 120 cp = LIST_FIRST(&gp->consumer); 121 sc = gp->softc; 122 switch (bp->bio_cmd) { 123 case BIO_READ: 124 bp2 = g_clone_bio(bp); 125 bp2->bio_done = g_aes_read_done; 126 bp2->bio_offset += sc->sectorsize; 127 g_io_request(bp2, cp); 128 break; 129 case BIO_WRITE: 130 bp2 = g_clone_bio(bp); 131 bp2->bio_done = g_aes_write_done; 132 bp2->bio_offset += sc->sectorsize; 133 bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK); 134 b = bp->bio_data; 135 e = bp->bio_data; 136 e += bp->bio_length; 137 p2 = bp2->bio_data; 138 for (p1 = b; p1 < e; p1 += sc->sectorsize) { 139 rijndael_blockEncrypt(&sc->ci, &sc->ekey, 140 p1, sc->sectorsize * 8, p2); 141 p2 += sc->sectorsize; 142 } 143 g_io_request(bp2, cp); 144 break; 145 case BIO_GETATTR: 146 case BIO_SETATTR: 147 if (g_haveattr_off_t(bp, "GEOM::mediasize", sc->mediasize)) 148 return; 149 if (g_haveattr_int(bp, "GEOM::sectorsize", sc->sectorsize)) 150 return; 151 bp2 = g_clone_bio(bp); 152 bp2->bio_done = g_std_done; 153 bp2->bio_offset += sc->sectorsize; 154 g_io_request(bp2, cp); 155 break; 156 default: 157 bp->bio_error = EOPNOTSUPP; 158 g_io_deliver(bp); 159 return; 160 } 161 return; 162} 163 164static void 165g_aes_orphan(struct g_consumer *cp) 166{ 167 struct g_geom *gp; 168 struct g_provider *pp; 169 int error; 170 171 g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name); 172 g_topology_assert(); 173 KASSERT(cp->provider->error != 0, 174 ("g_aes_orphan with error == 0")); 175 176 gp = cp->geom; 177 gp->flags |= G_GEOM_WITHER; 178 error = cp->provider->error; 179 LIST_FOREACH(pp, &gp->provider, provider) 180 g_orphan_provider(pp, error); 181 return; 182} 183 184static int 185g_aes_access(struct g_provider *pp, int dr, int dw, int de) 186{ 187 struct g_geom *gp; 188 struct g_consumer *cp; 189 190 gp = pp->geom; 191 cp = LIST_FIRST(&gp->consumer); 192 /* On first open, grab an extra "exclusive" bit */ 193 if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) 194 de++; 195 /* ... and let go of it on last close */ 196 if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) 197 de--; 198 return (g_access_rel(cp, dr, dw, de)); 199} 200 201static struct g_geom * 202g_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 203{ 204 struct g_geom *gp; 205 struct g_consumer *cp; 206 struct g_aes_softc *sc; 207 int error; 208 u_int sectorsize; 209 off_t mediasize; 210 u_char *buf; 211 212 g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name); 213 g_topology_assert(); 214 gp = g_new_geomf(mp, "%s.aes", pp->name); 215 gp->start = g_aes_start; 216 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_dettach(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, §orsize); 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_dettach(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_INITSTUFF 272}; 273 274DECLARE_GEOM_CLASS(g_aes_class, g_aes); 275