g_bde_lock.c revision 106407
1105464Sphk/*- 2105464Sphk * Copyright (c) 2002 Poul-Henning Kamp 3105464Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 4105464Sphk * All rights reserved. 5105464Sphk * 6105464Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7105464Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 8105464Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9105464Sphk * DARPA CHATS research program. 10105464Sphk * 11105464Sphk * Redistribution and use in source and binary forms, with or without 12105464Sphk * modification, are permitted provided that the following conditions 13105464Sphk * are met: 14105464Sphk * 1. Redistributions of source code must retain the above copyright 15105464Sphk * notice, this list of conditions and the following disclaimer. 16105464Sphk * 2. Redistributions in binary form must reproduce the above copyright 17105464Sphk * notice, this list of conditions and the following disclaimer in the 18105464Sphk * documentation and/or other materials provided with the distribution. 19105464Sphk * 20105464Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21105464Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22105464Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23105464Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24105464Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25105464Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26105464Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27105464Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28105464Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29105464Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30105464Sphk * SUCH DAMAGE. 31105464Sphk * 32105464Sphk * $FreeBSD: head/sys/geom/bde/g_bde_lock.c 106407 2002-11-04 09:27:01Z phk $ 33105464Sphk * 34105464Sphk * This souce file contains routines which operates on the lock sectors, both 35105464Sphk * for the kernel and the userland program gbde(1). 36105464Sphk * 37105464Sphk */ 38105464Sphk 39105464Sphk#include <sys/param.h> 40105464Sphk#include <sys/queue.h> 41105464Sphk#include <sys/stdint.h> 42105464Sphk#include <sys/lock.h> 43105464Sphk#include <sys/mutex.h> 44105464Sphk#include <sys/md5.h> 45105464Sphk 46105464Sphk#ifdef _KERNEL 47105464Sphk#include <sys/malloc.h> 48105464Sphk#include <sys/systm.h> 49105464Sphk#else 50106407Sphk#include <err.h> 51106407Sphk#define CTASSERT(foo) 52106407Sphk#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 53105464Sphk#include <errno.h> 54105464Sphk#include <string.h> 55105464Sphk#include <stdlib.h> 56105464Sphk#include <stdio.h> 57105464Sphk#define g_free(foo) free(foo) 58105464Sphk#endif 59105464Sphk 60106407Sphk#include <crypto/rijndael/rijndael.h> 61106407Sphk#include <crypto/sha2/sha2.h> 62106407Sphk 63105464Sphk#include <geom/geom.h> 64105464Sphk#include <geom/bde/g_bde.h> 65105464Sphk 66105464Sphk/* 67106407Sphk * Hash the raw pass-phrase. 68105464Sphk * 69106407Sphk * Security objectives: produce from the pass-phrase a fixed length 70106407Sphk * bytesequence with PRN like properties in a reproducible way retaining 71106407Sphk * as much entropy from the pass-phrase as possible. 72105464Sphk * 73106407Sphk * SHA2-512 makes this easy. 74105464Sphk */ 75105464Sphk 76105464Sphkvoid 77106407Sphkg_bde_hash_pass(struct g_bde_softc *sc, const void *input, u_int len) 78105464Sphk{ 79106407Sphk SHA512_CTX cx; 80105464Sphk 81106407Sphk SHA512_Init(&cx); 82106407Sphk SHA512_Update(&cx, input, len); 83106407Sphk SHA512_Final(sc->sha2, &cx); 84105464Sphk} 85105464Sphk 86105464Sphk/* 87106407Sphk * Encode/Decode the lock structure in byte-sequence format. 88105464Sphk * 89106407Sphk * Security objectives: Store in pass-phrase dependent variant format. 90105464Sphk * 91106407Sphk * C-structure packing and byte-endianess depends on architecture, compiler 92106407Sphk * and compiler options. Writing raw structures to disk is therefore a bad 93106407Sphk * idea in these enlightend days. 94106407Sphk * 95106407Sphk * We spend a fraction of the key-material on shuffling the fields around 96106407Sphk * so they will be stored in an unpredictable sequence. 97106407Sphk * 98106407Sphk * For each byte of the key-material we derive two field indexes, and swap 99106407Sphk * the position of those two fields. 100106407Sphk * 101106407Sphk * I have not worked out the statistical properties of this shuffle, but 102106407Sphk * given that the key-material has PRN properties, the primary objective 103106407Sphk * of making it hard to figure out which bits are where in the lock sector 104106407Sphk * is sufficiently fulfilled. 105106407Sphk * 106106407Sphk * We include (and shuffle) an extra hash field in the stored version for 107106407Sphk * identification and versioning purposes. This field contains the MD5 hash 108106407Sphk * of a version identifier (currently "0000") followed by the stored lock 109106407Sphk * sector byte-sequence substituting zero bytes for the hash field. 110106407Sphk * 111106407Sphk * The stored keysequence is protected by AES/256/CBC elsewhere in the code 112106407Sphk * so the fact that the generated byte sequence has a much higher than 113106407Sphk * average density of zero bits (from the numeric fields) is not currently 114106407Sphk * a concern. 115106407Sphk * 116106407Sphk * Should this later become a concern, a simple software update and 117106407Sphk * pass-phrase change can remedy the situation. One possible solution 118106407Sphk * could be to XOR the numeric fields with a key-material derived PRN. 119106407Sphk * 120106407Sphk * The chosen shuffle algorithm only works as long as we have no more than 16 121106407Sphk * fields in the stored part of the lock structure (hence the CTASSERT below). 122105464Sphk */ 123105464Sphk 124106407SphkCTASSERT(NLOCK_FIELDS <= 16); 125106407Sphk 126106407Sphkstatic void 127106407Sphkg_bde_shuffle_lock(struct g_bde_softc *sc, int *buf) 128105464Sphk{ 129106407Sphk int i, j, k, l; 130105464Sphk 131106407Sphk /* Assign the fields sequential positions */ 132106407Sphk for(i = 0; i < NLOCK_FIELDS; i++) 133106407Sphk buf[i] = i; 134106407Sphk 135106407Sphk /* Then mix it all up */ 136106407Sphk for(i = 48; i < sizeof(sc->sha2); i++) { 137106407Sphk j = sc->sha2[i] % NLOCK_FIELDS; 138106407Sphk k = (sc->sha2[i] / NLOCK_FIELDS) % NLOCK_FIELDS; 139106407Sphk l = buf[j]; 140106407Sphk buf[j] = buf[k]; 141106407Sphk buf[k] = l; 142106407Sphk } 143105464Sphk} 144105464Sphk 145106407Sphkint 146106407Sphkg_bde_encode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr) 147105464Sphk{ 148106407Sphk int shuffle[NLOCK_FIELDS]; 149106407Sphk u_char *hash, *p; 150106407Sphk int i; 151106407Sphk MD5_CTX c; 152106407Sphk 153105464Sphk p = ptr; 154106407Sphk hash = NULL; 155106407Sphk g_bde_shuffle_lock(sc, shuffle); 156106407Sphk for (i = 0; i < NLOCK_FIELDS; i++) { 157106407Sphk switch(shuffle[i]) { 158106407Sphk case 0: 159106407Sphk g_enc_le8(p, gl->sector0); 160106407Sphk p += 8; 161106407Sphk break; 162106407Sphk case 1: 163106407Sphk g_enc_le8(p, gl->sectorN); 164106407Sphk p += 8; 165106407Sphk break; 166106407Sphk case 2: 167106407Sphk g_enc_le8(p, gl->keyoffset); 168106407Sphk p += 8; 169106407Sphk break; 170106407Sphk case 3: 171106407Sphk g_enc_le4(p, gl->sectorsize); 172106407Sphk p += 4; 173106407Sphk break; 174106407Sphk case 4: 175106407Sphk g_enc_le4(p, gl->flags); 176106407Sphk p += 4; 177106407Sphk break; 178106407Sphk case 5: 179106407Sphk case 6: 180106407Sphk case 7: 181106407Sphk case 8: 182106407Sphk g_enc_le8(p, gl->lsector[shuffle[i] - 5]); 183106407Sphk p += 8; 184106407Sphk break; 185106407Sphk case 9: 186106407Sphk bcopy(gl->spare, p, sizeof gl->spare); 187106407Sphk p += sizeof gl->spare; 188106407Sphk break; 189106407Sphk case 10: 190106407Sphk bcopy(gl->salt, p, sizeof gl->salt); 191106407Sphk p += sizeof gl->salt; 192106407Sphk break; 193106407Sphk case 11: 194106407Sphk bcopy(gl->mkey, p, sizeof gl->mkey); 195106407Sphk p += sizeof gl->mkey; 196106407Sphk break; 197106407Sphk case 12: 198106407Sphk bzero(p, 16); 199106407Sphk hash = p; 200106407Sphk p += 16; 201106407Sphk break; 202106407Sphk } 203106407Sphk } 204106407Sphk if(ptr + G_BDE_LOCKSIZE != p) 205106407Sphk return(-1); 206106407Sphk if (hash == NULL) 207106407Sphk return(-1); 208106407Sphk MD5Init(&c); 209106407Sphk MD5Update(&c, "0000", 4); /* Versioning */ 210106407Sphk MD5Update(&c, ptr, G_BDE_LOCKSIZE); 211106407Sphk MD5Final(hash, &c); 212106407Sphk return(0); 213105464Sphk} 214105464Sphk 215106407Sphkint 216106407Sphkg_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr) 217105464Sphk{ 218106407Sphk int shuffle[NLOCK_FIELDS]; 219106407Sphk u_char *p; 220106407Sphk u_char hash[16], hash2[16]; 221106407Sphk MD5_CTX c; 222106407Sphk int i; 223105464Sphk 224105464Sphk p = ptr; 225106407Sphk g_bde_shuffle_lock(sc, shuffle); 226106407Sphk for (i = 0; i < NLOCK_FIELDS; i++) { 227106407Sphk switch(shuffle[i]) { 228106407Sphk case 0: 229106407Sphk gl->sector0 = g_dec_le8(p); 230106407Sphk p += 8; 231106407Sphk break; 232106407Sphk case 1: 233106407Sphk gl->sectorN = g_dec_le8(p); 234106407Sphk p += 8; 235106407Sphk break; 236106407Sphk case 2: 237106407Sphk gl->keyoffset = g_dec_le8(p); 238106407Sphk p += 8; 239106407Sphk break; 240106407Sphk case 3: 241106407Sphk gl->sectorsize = g_dec_le4(p); 242106407Sphk p += 4; 243106407Sphk break; 244106407Sphk case 4: 245106407Sphk gl->flags = g_dec_le4(p); 246106407Sphk p += 4; 247106407Sphk break; 248106407Sphk case 5: 249106407Sphk case 6: 250106407Sphk case 7: 251106407Sphk case 8: 252106407Sphk gl->lsector[shuffle[i] - 5] = g_dec_le8(p); 253106407Sphk p += 8; 254106407Sphk break; 255106407Sphk case 9: 256106407Sphk bcopy(p, gl->spare, sizeof gl->spare); 257106407Sphk p += sizeof gl->spare; 258106407Sphk break; 259106407Sphk case 10: 260106407Sphk bcopy(p, gl->salt, sizeof gl->salt); 261106407Sphk p += sizeof gl->salt; 262106407Sphk break; 263106407Sphk case 11: 264106407Sphk bcopy(p, gl->mkey, sizeof gl->mkey); 265106407Sphk p += sizeof gl->mkey; 266106407Sphk break; 267106407Sphk case 12: 268106407Sphk bcopy(p, hash2, sizeof hash2); 269106407Sphk bzero(p, sizeof hash2); 270106407Sphk p += sizeof hash2; 271106407Sphk break; 272106407Sphk } 273105464Sphk } 274106407Sphk if(ptr + G_BDE_LOCKSIZE != p) 275106407Sphk return(-1); 276106407Sphk MD5Init(&c); 277106407Sphk MD5Update(&c, "0000", 4); /* Versioning */ 278106407Sphk MD5Update(&c, ptr, G_BDE_LOCKSIZE); 279106407Sphk MD5Final(hash, &c); 280106407Sphk if (bcmp(hash, hash2, sizeof hash2)) 281106407Sphk return (1); 282106407Sphk return (0); 283105464Sphk} 284105464Sphk 285105464Sphk/* 286106407Sphk * Encode/Decode the locksector address ("metadata") with key-material. 287106407Sphk * 288106407Sphk * Security objectives: Encode/Decode the metadata encrypted by key-material. 289106407Sphk * 290106407Sphk * A simple AES/128/CBC will do. We take care to always store the metadata 291106407Sphk * in the same endianess to make it MI. 292106407Sphk * 293106407Sphk * In the typical case the metadata is stored in encrypted format in sector 294106407Sphk * zero on the media, but at the users discretion or if the piece of the 295106407Sphk * device used (sector0...sectorN) does not contain sector zero, it can 296106407Sphk * be stored in a filesystem or on a PostIt. 297106407Sphk * 298106407Sphk * The inability to easily locate the lock sectors makes an attack on a 299106407Sphk * cold disk much less attractive, without unduly inconveniencing the 300106407Sphk * legitimate user who can feasibly do a brute-force scan if the metadata 301106407Sphk * was lost. 302105464Sphk */ 303105464Sphk 304105464Sphkint 305106407Sphkg_bde_keyloc_encrypt(struct g_bde_softc *sc, uint64_t *input, void *output) 306105464Sphk{ 307106407Sphk u_char buf[16]; 308105464Sphk keyInstance ki; 309105464Sphk cipherInstance ci; 310105464Sphk 311106407Sphk g_enc_le8(buf, input[0]); 312106407Sphk g_enc_le8(buf + 8, input[1]); 313106407Sphk AES_init(&ci); 314106407Sphk AES_makekey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, sc->sha2 + 0); 315106407Sphk AES_encrypt(&ci, &ki, buf, output, sizeof buf); 316106407Sphk bzero(buf, sizeof buf); 317105464Sphk bzero(&ci, sizeof ci); 318105512Sphk bzero(&ki, sizeof ki); 319105464Sphk return (0); 320105464Sphk} 321105464Sphk 322105464Sphkint 323106407Sphkg_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, uint64_t *output) 324105464Sphk{ 325105464Sphk keyInstance ki; 326105464Sphk cipherInstance ci; 327106407Sphk u_char buf[16]; 328105464Sphk 329106407Sphk AES_init(&ci); 330106407Sphk AES_makekey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, sc->sha2 + 0); 331106407Sphk AES_decrypt(&ci, &ki, input, buf, sizeof buf); 332106407Sphk output[0] = g_dec_le8(buf); 333106407Sphk output[1] = g_dec_le8(buf + 8); 334106407Sphk bzero(buf, sizeof buf); 335105464Sphk bzero(&ci, sizeof ci); 336105512Sphk bzero(&ki, sizeof ki); 337105464Sphk return (0); 338105464Sphk} 339105464Sphk 340105464Sphk/* 341106407Sphk * Find and Encode/Decode lock sectors. 342106407Sphk * 343106407Sphk * Security objective: given the pass-phrase, find, decrypt, decode and 344106407Sphk * validate the lock sector contents. 345106407Sphk * 346106407Sphk * For ondisk metadata we cannot know beforehand which of the lock sectors 347106407Sphk * a given pass-phrase opens so we must try each of the metadata copies in 348106407Sphk * sector zero in turn. If metadata was passed as an argument, we don't 349106407Sphk * have this problem. 350106407Sphk * 351105464Sphk */ 352105464Sphk 353105512Sphkstatic int 354106407Sphkg_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey) 355105464Sphk{ 356106407Sphk u_char *buf, *q; 357105464Sphk struct g_bde_key *gl; 358105464Sphk uint64_t off[2]; 359105464Sphk int error, m, i; 360105464Sphk keyInstance ki; 361105464Sphk cipherInstance ci; 362105464Sphk 363105464Sphk gl = &sc->key; 364106407Sphk 365106407Sphk /* Try to decrypt the metadata */ 366105464Sphk error = g_bde_keyloc_decrypt(sc, meta, off); 367105464Sphk if (error) 368105464Sphk return(error); 369105464Sphk 370106407Sphk /* loose the random part */ 371106407Sphk off[1] = 0; 372106407Sphk 373106407Sphk /* If it points ito thin blue air, forget it */ 374105464Sphk if (off[0] + G_BDE_LOCKSIZE > (uint64_t)mediasize) { 375106407Sphk off[0] = 0; 376105512Sphk return (EINVAL); 377105464Sphk } 378106407Sphk 379106407Sphk /* The lock data may span two physical sectors. */ 380106407Sphk 381105464Sphk m = 1; 382105464Sphk if (off[0] % sectorsize > sectorsize - G_BDE_LOCKSIZE) 383105464Sphk m++; 384106407Sphk 385106407Sphk /* Read the suspected sector(s) */ 386105464Sphk buf = g_read_data(sc->consumer, 387105464Sphk off[0] - (off[0] % sectorsize), 388105464Sphk m * sectorsize, &error); 389105464Sphk if (buf == NULL) { 390105464Sphk off[0] = 0; 391105464Sphk return(error); 392105464Sphk } 393105464Sphk 394106407Sphk /* Find the byte-offset of the stored byte sequence */ 395105464Sphk q = buf + off[0] % sectorsize; 396105464Sphk 397106407Sphk /* If it is all zero, somebody nuked our lock sector */ 398105512Sphk for (i = 0; i < G_BDE_LOCKSIZE; i++) 399105464Sphk off[1] += q[i]; 400105464Sphk if (off[1] == 0) { 401105464Sphk off[0] = 0; 402105464Sphk g_free(buf); 403105464Sphk return (ESRCH); 404105464Sphk } 405105464Sphk 406106407Sphk /* Decrypt the byte-sequence in place */ 407106407Sphk AES_init(&ci); 408106407Sphk AES_makekey(&ki, DIR_DECRYPT, 256, sc->sha2 + 16); 409106407Sphk AES_decrypt(&ci, &ki, q, q, G_BDE_LOCKSIZE); 410106407Sphk 411106407Sphk /* Decode the byte-sequence */ 412106407Sphk i = g_bde_decode_lock(sc, gl, q); 413106407Sphk q = NULL; 414106407Sphk if (i < 0) { 415105464Sphk off[0] = 0; 416106407Sphk return (EDOOFUS); /* Programming error */ 417106407Sphk } else if (i > 0) { 418106407Sphk off[0] = 0; 419106407Sphk return (ENOTDIR); /* Hash didn't match */ 420105464Sphk } 421105464Sphk 422105464Sphk bzero(buf, sectorsize * m); 423105464Sphk g_free(buf); 424105464Sphk 425106407Sphk /* If the masterkey is all zeros, user destroyed it */ 426105464Sphk off[1] = 0; 427106226Sphk for (i = 0; i < (int)sizeof(gl->mkey); i++) 428106226Sphk off[1] += gl->mkey[i]; 429106407Sphk if (off[1] == 0) 430106407Sphk return (ENOENT); 431105464Sphk 432106407Sphk /* Finally, find out which key was used by matching the byte offset */ 433105464Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 434105464Sphk if (nkey != NULL && off[0] == gl->lsector[i]) 435105464Sphk *nkey = i; 436106407Sphk off[0] = 0; 437105464Sphk return (0); 438105464Sphk} 439105512Sphk 440105512Sphkint 441106407Sphkg_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey) 442105512Sphk{ 443105512Sphk u_char *buf, buf1[16]; 444105512Sphk int error, e, i; 445105512Sphk 446106407Sphk /* set up the key-material */ 447106407Sphk bcopy(keymat, sc->sha2, SHA512_DIGEST_LENGTH); 448106407Sphk 449106407Sphk /* If passed-in metadata is non-zero, use it */ 450105512Sphk bzero(buf1, sizeof buf1); 451105512Sphk if (bcmp(buf1, meta, sizeof buf1)) 452106407Sphk return (g_bde_decrypt_lockx(sc, meta, mediasize, 453105512Sphk sectorsize, nkey)); 454105512Sphk 455106407Sphk /* Read sector zero */ 456105512Sphk buf = g_read_data(sc->consumer, 0, sectorsize, &error); 457105512Sphk if (buf == NULL) 458105512Sphk return(error); 459106407Sphk 460106407Sphk /* Try each index in turn, save indicative errors for final result */ 461106407Sphk error = EINVAL; 462105512Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) { 463106407Sphk e = g_bde_decrypt_lockx(sc, buf + i * 16, mediasize, 464105512Sphk sectorsize, nkey); 465106407Sphk /* Success or destroyed master key terminates */ 466105512Sphk if (e == 0 || e == ENOENT) { 467105512Sphk error = e; 468105512Sphk break; 469105512Sphk } 470106407Sphk if (e != 0 && error == EINVAL) 471105512Sphk error = e; 472105512Sphk } 473105512Sphk g_free(buf); 474105512Sphk return (error); 475105512Sphk} 476