geom_aes.c revision 152967
11558Srgrimes/*- 21558Srgrimes * Copyright (c) 2002 Poul-Henning Kamp 31558Srgrimes * Copyright (c) 2002 Networks Associates Technology, Inc. 41558Srgrimes * All rights reserved. 51558Srgrimes * 61558Srgrimes * This software was developed for the FreeBSD Project by Poul-Henning Kamp 71558Srgrimes * and NAI Labs, the Security Research Division of Network Associates, Inc. 81558Srgrimes * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 91558Srgrimes * DARPA CHATS research program. 101558Srgrimes * 111558Srgrimes * Redistribution and use in source and binary forms, with or without 121558Srgrimes * modification, are permitted provided that the following conditions 131558Srgrimes * are met: 141558Srgrimes * 1. Redistributions of source code must retain the above copyright 151558Srgrimes * notice, this list of conditions and the following disclaimer. 161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171558Srgrimes * notice, this list of conditions and the following disclaimer in the 181558Srgrimes * documentation and/or other materials provided with the distribution. 191558Srgrimes * 3. The names of the authors may not be used to endorse or promote 201558Srgrimes * products derived from this software without specific prior written 211558Srgrimes * permission. 221558Srgrimes * 231558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 241558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 271558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331558Srgrimes * SUCH DAMAGE. 341558Srgrimes */ 3537664Scharnier 3637664Scharnier/* 3737664Scharnier * This method provides AES encryption with a compiled in key (default 381558Srgrimes * all zeroes). 391558Srgrimes * 401558Srgrimes * XXX: This could probably save a lot of code by pretending to be a slicer. 4137664Scharnier */ 4237664Scharnier 4337664Scharnier#include <sys/cdefs.h> 4437664Scharnier__FBSDID("$FreeBSD: head/sys/geom/geom_aes.c 152967 2005-11-30 19:24:51Z sobomax $"); 4537775Sbde 461558Srgrimes#include <sys/param.h> 471558Srgrimes#include <sys/systm.h> 481558Srgrimes#include <sys/kernel.h> 491558Srgrimes#include <sys/conf.h> 501558Srgrimes#include <sys/bio.h> 511558Srgrimes#include <sys/malloc.h> 521558Srgrimes#include <sys/lock.h> 531558Srgrimes#include <sys/mutex.h> 541558Srgrimes#include <sys/libkern.h> 551558Srgrimes#include <sys/endian.h> 561558Srgrimes#include <sys/md5.h> 5737707Scharnier#include <sys/errno.h> 5837707Scharnier#include <geom/geom.h> 591558Srgrimes 6023682Speter#include <crypto/rijndael/rijndael-api-fst.h> 611558Srgrimes 621558Srgrimes#define AES_CLASS_NAME "AES" 6337664Scharnier 641558Srgrimes#define MASTER_KEY_LENGTH (1024/8) 651558Srgrimes 661558Srgrimesstatic const u_char *aes_magic = "<<FreeBSD-GEOM-AES>>"; 671558Srgrimesstatic const u_char *aes_magic_random = "<<FreeBSD-GEOM-AES-RANDOM>>"; 681558Srgrimesstatic const u_char *aes_magic_test = "<<FreeBSD-GEOM-AES-TEST>>"; 691558Srgrimes 701558Srgrimes 711558Srgrimesstruct g_aes_softc { 7237664Scharnier enum { 7337664Scharnier KEY_ZERO, 7437664Scharnier KEY_RANDOM, 7537664Scharnier KEY_TEST 7637664Scharnier } keying; 771558Srgrimes u_int sectorsize; 781558Srgrimes off_t mediasize; 7937707Scharnier cipherInstance ci; 8037707Scharnier u_char master_key[MASTER_KEY_LENGTH]; 811558Srgrimes}; 821558Srgrimes 831558Srgrimes/* 841558Srgrimes * Generate a sectorkey from the masterkey and the offset position. 851558Srgrimes * 861558Srgrimes * For KEY_ZERO we just return a key of all zeros. 871558Srgrimes * 881558Srgrimes * We feed the sector byte offset, 16 bytes of the master-key and 891558Srgrimes * the sector byte offset once more to MD5. 901558Srgrimes * The sector byte offset is converted to little-endian format first 911558Srgrimes * to support multi-architecture operation. 921558Srgrimes * We use 16 bytes from the master-key starting at the logical sector 931558Srgrimes * number modulus he length of the master-key. If need be we wrap 941558Srgrimes * around to the start of the master-key. 951558Srgrimes */ 961558Srgrimes 971558Srgrimesstatic void 981558Srgrimesg_aes_makekey(struct g_aes_softc *sc, off_t off, keyInstance *ki, int dir) 991558Srgrimes{ 1001558Srgrimes MD5_CTX cx; 1011558Srgrimes u_int64_t u64; 1021558Srgrimes u_int u, u1; 1031558Srgrimes u_char *p, buf[16]; 1041558Srgrimes 1051558Srgrimes if (sc->keying == KEY_ZERO) { 1061558Srgrimes rijndael_makeKey(ki, dir, 128, sc->master_key); 1071558Srgrimes return; 1081558Srgrimes } 1091558Srgrimes MD5Init(&cx); 1101558Srgrimes u64 = htole64(off); 1111558Srgrimes MD5Update(&cx, (u_char *)&u64, sizeof(u64)); 1121558Srgrimes u = off / sc->sectorsize; 1131558Srgrimes u %= sizeof sc->master_key; 1141558Srgrimes p = sc->master_key + u; 1151558Srgrimes if (u + 16 <= sizeof(sc->master_key)) { 1161558Srgrimes MD5Update(&cx, p, 16); 1171558Srgrimes } else { 1183271Sdg u1 = sizeof sc->master_key - u; 1193271Sdg MD5Update(&cx, p, u1); 1203271Sdg MD5Update(&cx, sc->master_key, 16 - u1); 1213271Sdg u1 = 0; /* destroy evidence */ 1223271Sdg } 1233271Sdg u = 0; /* destroy evidence */ 1243271Sdg MD5Update(&cx, (u_char *)&u64, sizeof(u64)); 1253271Sdg u64 = 0; /* destroy evidence */ 1263271Sdg MD5Final(buf, &cx); 1271558Srgrimes bzero(&cx, sizeof cx); /* destroy evidence */ 1283271Sdg rijndael_makeKey(ki, dir, 128, buf); 1291558Srgrimes bzero(buf, sizeof buf); /* destroy evidence */ 1301558Srgrimes 1311558Srgrimes} 1321558Srgrimes 1331558Srgrimesstatic void 1341558Srgrimesg_aes_read_done(struct bio *bp) 1351558Srgrimes{ 1361558Srgrimes struct g_geom *gp; 1371558Srgrimes struct g_aes_softc *sc; 1381558Srgrimes u_char *p, *b, *e, *sb; 1391558Srgrimes keyInstance dkey; 1401558Srgrimes off_t o; 1411558Srgrimes 1421558Srgrimes gp = bp->bio_from->geom; 1431558Srgrimes sc = gp->softc; 1441558Srgrimes sb = g_malloc(sc->sectorsize, M_WAITOK); 1453271Sdg b = bp->bio_data; 1463271Sdg e = bp->bio_data; 1473271Sdg e += bp->bio_length; 1483271Sdg o = bp->bio_offset - sc->sectorsize; 1493271Sdg for (p = b; p < e; p += sc->sectorsize) { 1503271Sdg g_aes_makekey(sc, o, &dkey, DIR_DECRYPT); 1513271Sdg rijndael_blockDecrypt(&sc->ci, &dkey, p, sc->sectorsize * 8, sb); 15232537Sbde bcopy(sb, p, sc->sectorsize); 1533467Sdg o += sc->sectorsize; 1543467Sdg } 1551558Srgrimes bzero(&dkey, sizeof dkey); /* destroy evidence */ 1563467Sdg bzero(sb, sc->sectorsize); /* destroy evidence */ 1571558Srgrimes g_free(sb); 1586192Sphk g_std_done(bp); 1596192Sphk} 1606192Sphk 1616192Sphkstatic void 1626192Sphkg_aes_write_done(struct bio *bp) 1636192Sphk{ 1646192Sphk 1651558Srgrimes bzero(bp->bio_data, bp->bio_length); /* destroy evidence */ 1666192Sphk g_free(bp->bio_data); 1676192Sphk g_std_done(bp); 1686192Sphk} 1696192Sphk 1701558Srgrimesstatic void 1711558Srgrimesg_aes_start(struct bio *bp) 1721558Srgrimes{ 1731558Srgrimes struct g_geom *gp; 1746192Sphk struct g_consumer *cp; 1756192Sphk struct g_aes_softc *sc; 1761558Srgrimes struct bio *bp2; 1771558Srgrimes u_char *p1, *p2, *b, *e; 1781558Srgrimes keyInstance ekey; 1791558Srgrimes off_t o; 1801558Srgrimes 1811558Srgrimes gp = bp->bio_to->geom; 1821558Srgrimes cp = LIST_FIRST(&gp->consumer); 1831558Srgrimes sc = gp->softc; 1841558Srgrimes switch (bp->bio_cmd) { 1851558Srgrimes case BIO_READ: 1861558Srgrimes bp2 = g_clone_bio(bp); 1871558Srgrimes if (bp2 == NULL) { 1881558Srgrimes g_io_deliver(bp, ENOMEM); 1891558Srgrimes return; 1901558Srgrimes } 1911558Srgrimes bp2->bio_done = g_aes_read_done; 1921558Srgrimes bp2->bio_offset += sc->sectorsize; 1931558Srgrimes g_io_request(bp2, cp); 1941558Srgrimes break; 1951558Srgrimes case BIO_WRITE: 1961558Srgrimes bp2 = g_clone_bio(bp); 1971558Srgrimes if (bp2 == NULL) { 1981558Srgrimes g_io_deliver(bp, ENOMEM); 1991558Srgrimes return; 2001558Srgrimes } 20110846Sdg bp2->bio_done = g_aes_write_done; 2021558Srgrimes bp2->bio_offset += sc->sectorsize; 2031558Srgrimes bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK); 2043550Sphk b = bp->bio_data; 2051558Srgrimes e = bp->bio_data; 2061558Srgrimes e += bp->bio_length; 2071558Srgrimes p2 = bp2->bio_data; 2081558Srgrimes o = bp->bio_offset; 2091558Srgrimes for (p1 = b; p1 < e; p1 += sc->sectorsize) { 2101558Srgrimes g_aes_makekey(sc, o, &ekey, DIR_ENCRYPT); 2111558Srgrimes rijndael_blockEncrypt(&sc->ci, &ekey, 2121558Srgrimes p1, sc->sectorsize * 8, p2); 21337664Scharnier p2 += sc->sectorsize; 21437664Scharnier o += sc->sectorsize; 21537664Scharnier } 2161558Srgrimes bzero(&ekey, sizeof ekey); /* destroy evidence */ 2171558Srgrimes g_io_request(bp2, cp); 2181558Srgrimes break; 2191558Srgrimes case BIO_GETATTR: 2201558Srgrimes bp2 = g_clone_bio(bp); 2211558Srgrimes if (bp2 == NULL) { 2221558Srgrimes g_io_deliver(bp, ENOMEM); 2231558Srgrimes return; 22426856Stegge } 2251558Srgrimes bp2->bio_done = g_std_done; 2261558Srgrimes bp2->bio_offset += sc->sectorsize; 2271558Srgrimes g_io_request(bp2, cp); 2281558Srgrimes break; 2291558Srgrimes default: 23037664Scharnier g_io_deliver(bp, EOPNOTSUPP); 23113140Speter return; 23223682Speter } 23323682Speter return; 23437664Scharnier} 23513140Speter 2361558Srgrimesstatic void 23737664Scharnierg_aes_orphan(struct g_consumer *cp) 2381558Srgrimes{ 2391558Srgrimes struct g_geom *gp; 2401558Srgrimes struct g_aes_softc *sc; 2411558Srgrimes 2421558Srgrimes g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name); 2431558Srgrimes g_topology_assert(); 2441558Srgrimes KASSERT(cp->provider->error != 0, 2451558Srgrimes ("g_aes_orphan with error == 0")); 2461558Srgrimes 2471558Srgrimes gp = cp->geom; 2483555Sjkh sc = gp->softc; 2491558Srgrimes g_wither_geom(gp, cp->provider->error); 25024359Simp bzero(sc, sizeof(struct g_aes_softc)); /* destroy evidence */ 2511558Srgrimes g_free(sc); 2521558Srgrimes return; 2531558Srgrimes} 2541558Srgrimes 2551558Srgrimesstatic int 2561558Srgrimesg_aes_access(struct g_provider *pp, int dr, int dw, int de) 2571558Srgrimes{ 2581558Srgrimes struct g_geom *gp; 2591558Srgrimes struct g_consumer *cp; 2601558Srgrimes 2611558Srgrimes gp = pp->geom; 2621558Srgrimes cp = LIST_FIRST(&gp->consumer); 2631558Srgrimes /* On first open, grab an extra "exclusive" bit */ 2641558Srgrimes if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) 2651558Srgrimes de++; 2661558Srgrimes /* ... and let go of it on last close */ 2673550Sphk if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) 2683550Sphk de--; 2693550Sphk return (g_access(cp, dr, dw, de)); 2701558Srgrimes} 2711558Srgrimes 27237664Scharnierstatic struct g_geom * 2731558Srgrimesg_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 2741558Srgrimes{ 2751558Srgrimes struct g_geom *gp; 2761558Srgrimes struct g_consumer *cp; 2771558Srgrimes struct g_aes_softc *sc; 2781558Srgrimes int error; 2791558Srgrimes u_int sectorsize; 2801558Srgrimes off_t mediasize; 2811558Srgrimes u_char *buf; 2821558Srgrimes 2831558Srgrimes g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name); 2841558Srgrimes g_topology_assert(); 2851558Srgrimes gp = g_new_geomf(mp, "%s.aes", pp->name); 28637664Scharnier cp = g_new_consumer(gp); 2871558Srgrimes g_attach(cp, pp); 2881558Srgrimes error = g_access(cp, 1, 0, 0); 2891558Srgrimes if (error) { 29037664Scharnier g_detach(cp); 2911558Srgrimes g_destroy_consumer(cp); 2921558Srgrimes g_destroy_geom(gp); 2931558Srgrimes return (NULL); 2941558Srgrimes } 2951558Srgrimes buf = NULL; 2961558Srgrimes g_topology_unlock(); 2971558Srgrimes do { 2981558Srgrimes if (gp->rank != 2) 29937664Scharnier break; 3001558Srgrimes sectorsize = cp->provider->sectorsize; 3011558Srgrimes mediasize = cp->provider->mediasize; 3021558Srgrimes buf = g_read_data(cp, 0, sectorsize, &error); 3031558Srgrimes if (buf == NULL) { 3041558Srgrimes break; 3051558Srgrimes } 3061558Srgrimes sc = g_malloc(sizeof(struct g_aes_softc), M_WAITOK | M_ZERO); 3071558Srgrimes if (!memcmp(buf, aes_magic, strlen(aes_magic))) { 3081558Srgrimes sc->keying = KEY_ZERO; 3091558Srgrimes } else if (!memcmp(buf, aes_magic_random, 3101558Srgrimes strlen(aes_magic_random))) { 31137664Scharnier sc->keying = KEY_RANDOM; 3121558Srgrimes } else if (!memcmp(buf, aes_magic_test, 3131558Srgrimes strlen(aes_magic_test))) { 3143271Sdg sc->keying = KEY_TEST; 31537664Scharnier } else { 3161558Srgrimes g_free(sc); 3173467Sdg break; 3183467Sdg } 3191558Srgrimes g_free(buf); 3201558Srgrimes gp->softc = sc; 3211558Srgrimes sc->sectorsize = sectorsize; 3224065Swollman sc->mediasize = mediasize - sectorsize; 3231558Srgrimes rijndael_cipherInit(&sc->ci, MODE_CBC, NULL); 3241558Srgrimes if (sc->keying == KEY_TEST) { 3251558Srgrimes int i; 3261558Srgrimes u_char *p; 3271558Srgrimes 3281558Srgrimes p = sc->master_key; 32937664Scharnier for (i = 0; i < (int)sizeof sc->master_key; i ++) 3301558Srgrimes *p++ = i; 3311558Srgrimes } 3321558Srgrimes if (sc->keying == KEY_RANDOM) { 3331558Srgrimes int i; 3341558Srgrimes u_int32_t u; 3351558Srgrimes u_char *p; 3361558Srgrimes 3371558Srgrimes p = sc->master_key; 3381558Srgrimes for (i = 0; i < (int)sizeof sc->master_key; i += sizeof u) { 33937664Scharnier u = arc4random(); 3401558Srgrimes *p++ = u; 3411558Srgrimes *p++ = u >> 8; 3421558Srgrimes *p++ = u >> 16; 3431558Srgrimes *p++ = u >> 24; 3441558Srgrimes } 3451558Srgrimes } 34610846Sdg g_topology_lock(); 3476202Sphk pp = g_new_providerf(gp, gp->name); 3481558Srgrimes pp->mediasize = mediasize - sectorsize; 3491558Srgrimes pp->sectorsize = sectorsize; 3501558Srgrimes g_error_provider(pp, 0); 35110846Sdg g_topology_unlock(); 3526202Sphk } while(0); 3531558Srgrimes g_topology_lock(); 3541558Srgrimes if (buf) 3551558Srgrimes g_free(buf); 3561558Srgrimes g_access(cp, -1, 0, 0); 3571558Srgrimes if (gp->softc != NULL) 3581558Srgrimes return (gp); 3591558Srgrimes g_detach(cp); 3601558Srgrimes g_destroy_consumer(cp); 3611558Srgrimes g_destroy_geom(gp); 3621558Srgrimes return (NULL); 3631558Srgrimes} 3641558Srgrimes 3651558Srgrimesstatic struct g_class g_aes_class = { 3661558Srgrimes .name = AES_CLASS_NAME, 3671558Srgrimes .version = G_VERSION, 3681558Srgrimes .taste = g_aes_taste, 3691558Srgrimes .start = g_aes_start, 3701558Srgrimes .orphan = g_aes_orphan, 37126856Stegge .spoiled = g_std_spoiled, 37226856Stegge .access = g_aes_access, 37326856Stegge}; 37426856Stegge 37526856SteggeDECLARE_GEOM_CLASS(g_aes_class, g_aes); 37626856Stegge