g_bde_lock.c revision 108052
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 108052 2002-12-18 19:57:27Z 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{ 129107450Sphk int j, k, l; 130107450Sphk u_int u; 131105464Sphk 132106407Sphk /* Assign the fields sequential positions */ 133107450Sphk for(u = 0; u < NLOCK_FIELDS; u++) 134107450Sphk buf[u] = u; 135106407Sphk 136106407Sphk /* Then mix it all up */ 137107450Sphk for(u = 48; u < sizeof(sc->sha2); u++) { 138107450Sphk j = sc->sha2[u] % NLOCK_FIELDS; 139107450Sphk k = (sc->sha2[u] / NLOCK_FIELDS) % NLOCK_FIELDS; 140106407Sphk l = buf[j]; 141106407Sphk buf[j] = buf[k]; 142106407Sphk buf[k] = l; 143106407Sphk } 144105464Sphk} 145105464Sphk 146106407Sphkint 147106407Sphkg_bde_encode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr) 148105464Sphk{ 149106407Sphk int shuffle[NLOCK_FIELDS]; 150106407Sphk u_char *hash, *p; 151106407Sphk int i; 152106407Sphk MD5_CTX c; 153106407Sphk 154105464Sphk p = ptr; 155106407Sphk hash = NULL; 156106407Sphk g_bde_shuffle_lock(sc, shuffle); 157106407Sphk for (i = 0; i < NLOCK_FIELDS; i++) { 158106407Sphk switch(shuffle[i]) { 159106407Sphk case 0: 160106407Sphk g_enc_le8(p, gl->sector0); 161106407Sphk p += 8; 162106407Sphk break; 163106407Sphk case 1: 164106407Sphk g_enc_le8(p, gl->sectorN); 165106407Sphk p += 8; 166106407Sphk break; 167106407Sphk case 2: 168106407Sphk g_enc_le8(p, gl->keyoffset); 169106407Sphk p += 8; 170106407Sphk break; 171106407Sphk case 3: 172106407Sphk g_enc_le4(p, gl->sectorsize); 173106407Sphk p += 4; 174106407Sphk break; 175106407Sphk case 4: 176106407Sphk g_enc_le4(p, gl->flags); 177106407Sphk p += 4; 178106407Sphk break; 179106407Sphk case 5: 180106407Sphk case 6: 181106407Sphk case 7: 182106407Sphk case 8: 183106407Sphk g_enc_le8(p, gl->lsector[shuffle[i] - 5]); 184106407Sphk p += 8; 185106407Sphk break; 186106407Sphk case 9: 187106407Sphk bcopy(gl->spare, p, sizeof gl->spare); 188106407Sphk p += sizeof gl->spare; 189106407Sphk break; 190106407Sphk case 10: 191106407Sphk bcopy(gl->salt, p, sizeof gl->salt); 192106407Sphk p += sizeof gl->salt; 193106407Sphk break; 194106407Sphk case 11: 195106407Sphk bcopy(gl->mkey, p, sizeof gl->mkey); 196106407Sphk p += sizeof gl->mkey; 197106407Sphk break; 198106407Sphk case 12: 199106407Sphk bzero(p, 16); 200106407Sphk hash = p; 201106407Sphk p += 16; 202106407Sphk break; 203106407Sphk } 204106407Sphk } 205106407Sphk if(ptr + G_BDE_LOCKSIZE != p) 206106407Sphk return(-1); 207106407Sphk if (hash == NULL) 208106407Sphk return(-1); 209106407Sphk MD5Init(&c); 210106407Sphk MD5Update(&c, "0000", 4); /* Versioning */ 211106407Sphk MD5Update(&c, ptr, G_BDE_LOCKSIZE); 212106407Sphk MD5Final(hash, &c); 213106407Sphk return(0); 214105464Sphk} 215105464Sphk 216106407Sphkint 217106407Sphkg_bde_decode_lock(struct g_bde_softc *sc, struct g_bde_key *gl, u_char *ptr) 218105464Sphk{ 219106407Sphk int shuffle[NLOCK_FIELDS]; 220106407Sphk u_char *p; 221106407Sphk u_char hash[16], hash2[16]; 222106407Sphk MD5_CTX c; 223106407Sphk int i; 224105464Sphk 225105464Sphk p = ptr; 226106407Sphk g_bde_shuffle_lock(sc, shuffle); 227106407Sphk for (i = 0; i < NLOCK_FIELDS; i++) { 228106407Sphk switch(shuffle[i]) { 229106407Sphk case 0: 230106407Sphk gl->sector0 = g_dec_le8(p); 231106407Sphk p += 8; 232106407Sphk break; 233106407Sphk case 1: 234106407Sphk gl->sectorN = g_dec_le8(p); 235106407Sphk p += 8; 236106407Sphk break; 237106407Sphk case 2: 238106407Sphk gl->keyoffset = g_dec_le8(p); 239106407Sphk p += 8; 240106407Sphk break; 241106407Sphk case 3: 242106407Sphk gl->sectorsize = g_dec_le4(p); 243106407Sphk p += 4; 244106407Sphk break; 245106407Sphk case 4: 246106407Sphk gl->flags = g_dec_le4(p); 247106407Sphk p += 4; 248106407Sphk break; 249106407Sphk case 5: 250106407Sphk case 6: 251106407Sphk case 7: 252106407Sphk case 8: 253106407Sphk gl->lsector[shuffle[i] - 5] = g_dec_le8(p); 254106407Sphk p += 8; 255106407Sphk break; 256106407Sphk case 9: 257106407Sphk bcopy(p, gl->spare, sizeof gl->spare); 258106407Sphk p += sizeof gl->spare; 259106407Sphk break; 260106407Sphk case 10: 261106407Sphk bcopy(p, gl->salt, sizeof gl->salt); 262106407Sphk p += sizeof gl->salt; 263106407Sphk break; 264106407Sphk case 11: 265106407Sphk bcopy(p, gl->mkey, sizeof gl->mkey); 266106407Sphk p += sizeof gl->mkey; 267106407Sphk break; 268106407Sphk case 12: 269106407Sphk bcopy(p, hash2, sizeof hash2); 270106407Sphk bzero(p, sizeof hash2); 271106407Sphk p += sizeof hash2; 272106407Sphk break; 273106407Sphk } 274105464Sphk } 275106407Sphk if(ptr + G_BDE_LOCKSIZE != p) 276106407Sphk return(-1); 277106407Sphk MD5Init(&c); 278106407Sphk MD5Update(&c, "0000", 4); /* Versioning */ 279106407Sphk MD5Update(&c, ptr, G_BDE_LOCKSIZE); 280106407Sphk MD5Final(hash, &c); 281106407Sphk if (bcmp(hash, hash2, sizeof hash2)) 282106407Sphk return (1); 283106407Sphk return (0); 284105464Sphk} 285105464Sphk 286105464Sphk/* 287106407Sphk * Encode/Decode the locksector address ("metadata") with key-material. 288106407Sphk * 289106407Sphk * Security objectives: Encode/Decode the metadata encrypted by key-material. 290106407Sphk * 291106407Sphk * A simple AES/128/CBC will do. We take care to always store the metadata 292106407Sphk * in the same endianess to make it MI. 293106407Sphk * 294106407Sphk * In the typical case the metadata is stored in encrypted format in sector 295106407Sphk * zero on the media, but at the users discretion or if the piece of the 296106407Sphk * device used (sector0...sectorN) does not contain sector zero, it can 297106407Sphk * be stored in a filesystem or on a PostIt. 298106407Sphk * 299106407Sphk * The inability to easily locate the lock sectors makes an attack on a 300106407Sphk * cold disk much less attractive, without unduly inconveniencing the 301106407Sphk * legitimate user who can feasibly do a brute-force scan if the metadata 302106407Sphk * was lost. 303105464Sphk */ 304105464Sphk 305105464Sphkint 306106407Sphkg_bde_keyloc_encrypt(struct g_bde_softc *sc, uint64_t *input, void *output) 307105464Sphk{ 308106407Sphk u_char buf[16]; 309105464Sphk keyInstance ki; 310105464Sphk cipherInstance ci; 311105464Sphk 312106407Sphk g_enc_le8(buf, input[0]); 313106407Sphk g_enc_le8(buf + 8, input[1]); 314106407Sphk AES_init(&ci); 315106407Sphk AES_makekey(&ki, DIR_ENCRYPT, G_BDE_KKEYBITS, sc->sha2 + 0); 316106407Sphk AES_encrypt(&ci, &ki, buf, output, sizeof buf); 317106407Sphk bzero(buf, sizeof buf); 318105464Sphk bzero(&ci, sizeof ci); 319105512Sphk bzero(&ki, sizeof ki); 320105464Sphk return (0); 321105464Sphk} 322105464Sphk 323105464Sphkint 324106407Sphkg_bde_keyloc_decrypt(struct g_bde_softc *sc, void *input, uint64_t *output) 325105464Sphk{ 326105464Sphk keyInstance ki; 327105464Sphk cipherInstance ci; 328106407Sphk u_char buf[16]; 329105464Sphk 330106407Sphk AES_init(&ci); 331106407Sphk AES_makekey(&ki, DIR_DECRYPT, G_BDE_KKEYBITS, sc->sha2 + 0); 332106407Sphk AES_decrypt(&ci, &ki, input, buf, sizeof buf); 333106407Sphk output[0] = g_dec_le8(buf); 334106407Sphk output[1] = g_dec_le8(buf + 8); 335106407Sphk bzero(buf, sizeof buf); 336105464Sphk bzero(&ci, sizeof ci); 337105512Sphk bzero(&ki, sizeof ki); 338105464Sphk return (0); 339105464Sphk} 340105464Sphk 341105464Sphk/* 342106407Sphk * Find and Encode/Decode lock sectors. 343106407Sphk * 344106407Sphk * Security objective: given the pass-phrase, find, decrypt, decode and 345106407Sphk * validate the lock sector contents. 346106407Sphk * 347106407Sphk * For ondisk metadata we cannot know beforehand which of the lock sectors 348106407Sphk * a given pass-phrase opens so we must try each of the metadata copies in 349106407Sphk * sector zero in turn. If metadata was passed as an argument, we don't 350106407Sphk * have this problem. 351106407Sphk * 352105464Sphk */ 353105464Sphk 354105512Sphkstatic int 355106407Sphkg_bde_decrypt_lockx(struct g_bde_softc *sc, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey) 356105464Sphk{ 357106407Sphk u_char *buf, *q; 358105464Sphk struct g_bde_key *gl; 359105464Sphk uint64_t off[2]; 360105464Sphk int error, m, i; 361105464Sphk keyInstance ki; 362105464Sphk cipherInstance ci; 363105464Sphk 364105464Sphk gl = &sc->key; 365106407Sphk 366106407Sphk /* Try to decrypt the metadata */ 367105464Sphk error = g_bde_keyloc_decrypt(sc, meta, off); 368105464Sphk if (error) 369105464Sphk return(error); 370105464Sphk 371106407Sphk /* loose the random part */ 372106407Sphk off[1] = 0; 373106407Sphk 374106407Sphk /* If it points ito thin blue air, forget it */ 375105464Sphk if (off[0] + G_BDE_LOCKSIZE > (uint64_t)mediasize) { 376106407Sphk off[0] = 0; 377105512Sphk return (EINVAL); 378105464Sphk } 379106407Sphk 380106407Sphk /* The lock data may span two physical sectors. */ 381106407Sphk 382105464Sphk m = 1; 383105464Sphk if (off[0] % sectorsize > sectorsize - G_BDE_LOCKSIZE) 384105464Sphk m++; 385106407Sphk 386106407Sphk /* Read the suspected sector(s) */ 387105464Sphk buf = g_read_data(sc->consumer, 388105464Sphk off[0] - (off[0] % sectorsize), 389105464Sphk m * sectorsize, &error); 390105464Sphk if (buf == NULL) { 391105464Sphk off[0] = 0; 392105464Sphk return(error); 393105464Sphk } 394105464Sphk 395106407Sphk /* Find the byte-offset of the stored byte sequence */ 396105464Sphk q = buf + off[0] % sectorsize; 397105464Sphk 398106407Sphk /* If it is all zero, somebody nuked our lock sector */ 399105512Sphk for (i = 0; i < G_BDE_LOCKSIZE; i++) 400105464Sphk off[1] += q[i]; 401105464Sphk if (off[1] == 0) { 402105464Sphk off[0] = 0; 403105464Sphk g_free(buf); 404105464Sphk return (ESRCH); 405105464Sphk } 406105464Sphk 407106407Sphk /* Decrypt the byte-sequence in place */ 408106407Sphk AES_init(&ci); 409106407Sphk AES_makekey(&ki, DIR_DECRYPT, 256, sc->sha2 + 16); 410106407Sphk AES_decrypt(&ci, &ki, q, q, G_BDE_LOCKSIZE); 411106407Sphk 412106407Sphk /* Decode the byte-sequence */ 413106407Sphk i = g_bde_decode_lock(sc, gl, q); 414106407Sphk q = NULL; 415106407Sphk if (i < 0) { 416105464Sphk off[0] = 0; 417106407Sphk return (EDOOFUS); /* Programming error */ 418106407Sphk } else if (i > 0) { 419106407Sphk off[0] = 0; 420106407Sphk return (ENOTDIR); /* Hash didn't match */ 421105464Sphk } 422105464Sphk 423105464Sphk bzero(buf, sectorsize * m); 424105464Sphk g_free(buf); 425105464Sphk 426106407Sphk /* If the masterkey is all zeros, user destroyed it */ 427105464Sphk off[1] = 0; 428106226Sphk for (i = 0; i < (int)sizeof(gl->mkey); i++) 429106226Sphk off[1] += gl->mkey[i]; 430106407Sphk if (off[1] == 0) 431106407Sphk return (ENOENT); 432105464Sphk 433108052Sphk /* If we have an unsorted lock-sequence, refuse */ 434108052Sphk if (gl->lsector[0] > gl->lsector[1] || 435108052Sphk gl->lsector[1] > gl->lsector[2] || 436108052Sphk gl->lsector[2] > gl->lsector[3]) 437108052Sphk return (EINVAL); 438108052Sphk 439106407Sphk /* Finally, find out which key was used by matching the byte offset */ 440105464Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 441105464Sphk if (nkey != NULL && off[0] == gl->lsector[i]) 442105464Sphk *nkey = i; 443106407Sphk off[0] = 0; 444105464Sphk return (0); 445105464Sphk} 446105512Sphk 447105512Sphkint 448106407Sphkg_bde_decrypt_lock(struct g_bde_softc *sc, u_char *keymat, u_char *meta, off_t mediasize, u_int sectorsize, u_int *nkey) 449105512Sphk{ 450105512Sphk u_char *buf, buf1[16]; 451105512Sphk int error, e, i; 452105512Sphk 453106407Sphk /* set up the key-material */ 454106407Sphk bcopy(keymat, sc->sha2, SHA512_DIGEST_LENGTH); 455106407Sphk 456106407Sphk /* If passed-in metadata is non-zero, use it */ 457105512Sphk bzero(buf1, sizeof buf1); 458105512Sphk if (bcmp(buf1, meta, sizeof buf1)) 459106407Sphk return (g_bde_decrypt_lockx(sc, meta, mediasize, 460105512Sphk sectorsize, nkey)); 461105512Sphk 462106407Sphk /* Read sector zero */ 463105512Sphk buf = g_read_data(sc->consumer, 0, sectorsize, &error); 464105512Sphk if (buf == NULL) 465105512Sphk return(error); 466106407Sphk 467106407Sphk /* Try each index in turn, save indicative errors for final result */ 468106407Sphk error = EINVAL; 469105512Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) { 470106407Sphk e = g_bde_decrypt_lockx(sc, buf + i * 16, mediasize, 471105512Sphk sectorsize, nkey); 472106407Sphk /* Success or destroyed master key terminates */ 473105512Sphk if (e == 0 || e == ENOENT) { 474105512Sphk error = e; 475105512Sphk break; 476105512Sphk } 477106407Sphk if (e != 0 && error == EINVAL) 478105512Sphk error = e; 479105512Sphk } 480105512Sphk g_free(buf); 481105512Sphk return (error); 482105512Sphk} 483