diff --git a/stand/libsa/geli/geliboot.c b/stand/libsa/geli/geliboot.c index 954a3ec34044..56499e96b295 100644 --- a/stand/libsa/geli/geliboot.c +++ b/stand/libsa/geli/geliboot.c @@ -1,400 +1,400 @@ /*- * Copyright (c) 2015 Allan Jude * Copyright (c) 2005-2011 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include "geliboot.h" #include "geliboot_internal.h" struct known_dev { char name[GELIDEV_NAMELEN]; struct geli_dev *gdev; SLIST_ENTRY(known_dev) entries; }; SLIST_HEAD(known_dev_list, known_dev) known_devs_head = SLIST_HEAD_INITIALIZER(known_devs_head); static geli_ukey saved_keys[GELI_MAX_KEYS]; static unsigned int nsaved_keys = 0; /* * Copy keys from local storage to the keybuf struct. * Destroy the local storage when finished. */ void geli_export_key_buffer(struct keybuf *fkeybuf) { unsigned int i; for (i = 0; i < nsaved_keys; i++) { fkeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_GELI; memcpy(fkeybuf->kb_ents[i].ke_data, saved_keys[i], G_ELI_USERKEYLEN); } fkeybuf->kb_nents = nsaved_keys; explicit_bzero(saved_keys, sizeof(saved_keys)); } /* * Copy keys from a keybuf struct into local storage. * Zero out the keybuf. */ void geli_import_key_buffer(struct keybuf *skeybuf) { unsigned int i; for (i = 0; i < skeybuf->kb_nents && i < GELI_MAX_KEYS; i++) { memcpy(saved_keys[i], skeybuf->kb_ents[i].ke_data, G_ELI_USERKEYLEN); explicit_bzero(skeybuf->kb_ents[i].ke_data, G_ELI_USERKEYLEN); skeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE; } nsaved_keys = skeybuf->kb_nents; skeybuf->kb_nents = 0; } void geli_add_key(geli_ukey key) { /* * If we run out of key space, the worst that will happen is * it will ask the user for the password again. */ if (nsaved_keys < GELI_MAX_KEYS) { memcpy(saved_keys[nsaved_keys], key, G_ELI_USERKEYLEN); nsaved_keys++; } } static int geli_findkey(struct geli_dev *gdev, u_char *mkey) { u_int keynum; int i; if (gdev->keybuf_slot >= 0) { if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[gdev->keybuf_slot], mkey, &keynum) == 0) { return (0); } } for (i = 0; i < nsaved_keys; i++) { if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[i], mkey, &keynum) == 0) { gdev->keybuf_slot = i; return (0); } } return (1); } /* * Read the last sector of a drive or partition and see if it is GELI encrypted. */ struct geli_dev * geli_taste(geli_readfunc readfunc, void *readpriv, daddr_t lastsector, const char *namefmt, ...) { va_list args; struct g_eli_metadata md; struct known_dev *kdev; struct geli_dev *gdev; u_char *buf; char devname[GELIDEV_NAMELEN]; int error; off_t alignsector; /* * Format the name into a temp buffer and use that to search for an * existing known_dev instance. If not found, this has the side effect * of initializing kdev to NULL. */ va_start(args, namefmt); vsnprintf(devname, sizeof(devname), namefmt, args); va_end(args); SLIST_FOREACH(kdev, &known_devs_head, entries) { if (strcmp(kdev->name, devname) == 0) return (kdev->gdev); } /* Determine whether the new device is geli-encrypted... */ if ((buf = malloc(DEV_GELIBOOT_BSIZE)) == NULL) goto out; alignsector = rounddown2(lastsector * DEV_BSIZE, DEV_GELIBOOT_BSIZE); if (alignsector + DEV_GELIBOOT_BSIZE > ((lastsector + 1) * DEV_BSIZE)) { /* Don't read past the end of the disk */ alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE - DEV_GELIBOOT_BSIZE; } error = readfunc(NULL, readpriv, alignsector, buf, DEV_GELIBOOT_BSIZE); if (error != 0) { goto out; } /* * We have a new known_device. Whether it's geli-encrypted or not, * record its existance so we can avoid doing IO to probe it next time. */ if ((kdev = malloc(sizeof(*kdev))) == NULL) goto out; strlcpy(kdev->name, devname, sizeof(kdev->name)); kdev->gdev = NULL; SLIST_INSERT_HEAD(&known_devs_head, kdev, entries); /* Extract the last 4k sector of the disk. */ error = eli_metadata_decode(buf, &md); if (error != 0) { /* Try the last 512 byte sector instead. */ error = eli_metadata_decode(buf + (DEV_GELIBOOT_BSIZE - DEV_BSIZE), &md); if (error != 0) { goto out; } } if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) { /* The GELIBOOT feature is not activated */ goto out; } if ((md.md_flags & G_ELI_FLAG_ONETIME)) { /* Swap device, skip it. */ goto out; } /* * It's geli-encrypted, create a geli_dev for it and link it into the * known_dev instance. */ gdev = malloc(sizeof(struct geli_dev)); if (gdev == NULL) goto out; gdev->part_end = lastsector; gdev->keybuf_slot = -1; gdev->md = md; gdev->name = kdev->name; eli_metadata_softc(&gdev->sc, &md, DEV_BSIZE, (lastsector + DEV_BSIZE) * DEV_BSIZE); kdev->gdev = gdev; out: free(buf); if (kdev == NULL) return (NULL); return (kdev->gdev); } /* * Attempt to decrypt the device. This will try existing keys first, then will * prompt for a passphrase if there are no existing keys that work. */ static int geli_probe(struct geli_dev *gdev, const char *passphrase, u_char *mkeyp) { u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp; u_int keynum; struct hmac_ctx ctx; int error; if (mkeyp != NULL) { memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN); explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN); goto found_key; } if (geli_findkey(gdev, mkey) == 0) { goto found_key; } g_eli_crypto_hmac_init(&ctx, NULL, 0); /* * Prepare Derived-Key from the user passphrase. */ if (gdev->md.md_iterations < 0) { /* XXX TODO: Support loading key files. */ return (1); } else if (gdev->md.md_iterations == 0) { g_eli_crypto_hmac_update(&ctx, gdev->md.md_salt, sizeof(gdev->md.md_salt)); g_eli_crypto_hmac_update(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); } else if (gdev->md.md_iterations > 0) { printf("Calculating GELI Decryption Key for %s %d" " iterations...\n", gdev->name, gdev->md.md_iterations); u_char dkey[G_ELI_USERKEYLEN]; pkcs5v2_genkey(dkey, sizeof(dkey), gdev->md.md_salt, sizeof(gdev->md.md_salt), passphrase, gdev->md.md_iterations); g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); explicit_bzero(dkey, sizeof(dkey)); } g_eli_crypto_hmac_final(&ctx, key, 0); error = g_eli_mkey_decrypt_any(&gdev->md, key, mkey, &keynum); if (error == -1) { explicit_bzero(mkey, sizeof(mkey)); explicit_bzero(key, sizeof(key)); printf("Bad GELI key: bad password?\n"); return (error); } else if (error != 0) { explicit_bzero(mkey, sizeof(mkey)); explicit_bzero(key, sizeof(key)); printf("Failed to decrypt GELI master key: %d\n", error); return (error); } else { /* Add key to keychain */ geli_add_key(key); explicit_bzero(&key, sizeof(key)); } found_key: /* Store the keys */ bcopy(mkey, gdev->sc.sc_mkey, sizeof(gdev->sc.sc_mkey)); bcopy(mkey, gdev->sc.sc_ivkey, sizeof(gdev->sc.sc_ivkey)); mkp = mkey + sizeof(gdev->sc.sc_ivkey); if ((gdev->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) { bcopy(mkp, gdev->sc.sc_ekey, G_ELI_DATAKEYLEN); } else { /* * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10) */ g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x10", 1, gdev->sc.sc_ekey, 0); } explicit_bzero(mkey, sizeof(mkey)); /* Initialize the per-sector IV. */ switch (gdev->sc.sc_ealgo) { case CRYPTO_AES_XTS: break; default: SHA256_Init(&gdev->sc.sc_ivctx); SHA256_Update(&gdev->sc.sc_ivctx, gdev->sc.sc_ivkey, sizeof(gdev->sc.sc_ivkey)); break; } return (0); } int geli_io(struct geli_dev *gdev, geli_op_t enc, off_t offset, u_char *buf, size_t bytes) { u_char iv[G_ELI_IVKEYLEN]; u_char *pbuf; int error; off_t dstoff; uint64_t keyno; size_t n, nsec, secsize; struct g_eli_key gkey; pbuf = buf; secsize = gdev->sc.sc_sectorsize; nsec = bytes / secsize; if (nsec == 0) { /* * A read of less than the GELI sector size has been * requested. The caller provided destination buffer may * not be big enough to boost the read to a full sector, * so just attempt to decrypt the truncated sector. */ secsize = bytes; nsec = 1; } for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) { g_eli_crypto_ivgen(&gdev->sc, dstoff, iv, G_ELI_IVKEYLEN); /* Get the key that corresponds to this offset. */ keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize; g_eli_key_fill(&gdev->sc, &gkey, keyno); error = geliboot_crypt(gdev->sc.sc_ealgo, enc, pbuf, secsize, - gkey.gek_key, gdev->sc.sc_ekeylen, iv); + gkey.gek_key, gdev->sc.sc_ekeylen, iv, sizeof(iv)); if (error != 0) { explicit_bzero(&gkey, sizeof(gkey)); printf("%s: Failed to %s!", __func__, enc ? "encrypt" : "decrypt"); return (error); } pbuf += secsize; } explicit_bzero(&gkey, sizeof(gkey)); return (0); } int geli_havekey(struct geli_dev *gdev) { u_char mkey[G_ELI_DATAIVKEYLEN]; int err; err = ENOENT; if (geli_findkey(gdev, mkey) == 0) { if (geli_probe(gdev, NULL, mkey) == 0) err = 0; explicit_bzero(mkey, sizeof(mkey)); } return (err); } int geli_passphrase(struct geli_dev *gdev, char *pw) { int i; /* TODO: Implement GELI keyfile(s) support */ for (i = 0; i < 3; i++) { /* Try cached passphrase */ if (i == 0 && pw[0] != '\0') { if (geli_probe(gdev, pw, NULL) == 0) { return (0); } } printf("GELI Passphrase for %s ", gdev->name); pwgets(pw, GELI_PW_MAXLEN, (gdev->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0); printf("\n"); if (geli_probe(gdev, pw, NULL) == 0) { return (0); } } return (1); } diff --git a/stand/libsa/geli/geliboot_crypto.c b/stand/libsa/geli/geliboot_crypto.c index 8478d2754d6f..fcc5d7bcd7fb 100644 --- a/stand/libsa/geli/geliboot_crypto.c +++ b/stand/libsa/geli/geliboot_crypto.c @@ -1,143 +1,144 @@ /*- * Copyright (c) 2005-2010 Pawel Jakub Dawidek * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include "geliboot_internal.h" #include "geliboot.h" int geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize, - const u_char *key, size_t keysize, u_char *iv) + const u_char *key, size_t keysize, u_char *iv, size_t ivlen) { keyInstance aeskey; cipherInstance cipher; struct aes_xts_ctx xtsctx, *ctxp; size_t xts_len; int err, blks, i; switch (algo) { case CRYPTO_AES_CBC: err = rijndael_makeKey(&aeskey, !enc, keysize, (const char *)key); if (err < 0) { printf("Failed to setup crypo keys: %d\n", err); return (err); } err = rijndael_cipherInit(&cipher, MODE_CBC, iv); if (err < 0) { printf("Failed to setup IV: %d\n", err); return (err); } switch (enc) { case GELI_DECRYPT: blks = rijndael_blockDecrypt(&cipher, &aeskey, data, datasize * 8, data); break; case GELI_ENCRYPT: blks = rijndael_blockEncrypt(&cipher, &aeskey, data, datasize * 8, data); break; } if (datasize != (blks / 8)) { printf("Failed to %s the entire input: %u != %zu\n", enc ? "decrypt" : "encrypt", blks, datasize); return (1); } break; case CRYPTO_AES_XTS: xts_len = keysize << 1; ctxp = &xtsctx; enc_xform_aes_xts.setkey(ctxp, key, xts_len / 8); - enc_xform_aes_xts.reinit(ctxp, iv); + enc_xform_aes_xts.reinit(ctxp, iv, ivlen); switch (enc) { case GELI_DECRYPT: for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { enc_xform_aes_xts.decrypt(ctxp, data + i, data + i); } break; case GELI_ENCRYPT: for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { enc_xform_aes_xts.encrypt(ctxp, data + i, data + i); } break; } break; default: printf("Unsupported crypto algorithm #%d\n", algo); return (1); } return (0); } static int g_eli_crypto_cipher(u_int algo, geli_op_t enc, u_char *data, size_t datasize, const u_char *key, size_t keysize) { u_char iv[keysize]; explicit_bzero(iv, sizeof(iv)); - return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv)); + return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv, + sizeof(iv))); } int g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, const u_char *key, size_t keysize) { /* We prefer AES-CBC for metadata protection. */ if (algo == CRYPTO_AES_XTS) algo = CRYPTO_AES_CBC; return (g_eli_crypto_cipher(algo, GELI_ENCRYPT, data, datasize, key, keysize)); } int g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, const u_char *key, size_t keysize) { /* We prefer AES-CBC for metadata protection. */ if (algo == CRYPTO_AES_XTS) algo = CRYPTO_AES_CBC; return (g_eli_crypto_cipher(algo, GELI_DECRYPT, data, datasize, key, keysize)); } diff --git a/stand/libsa/geli/geliboot_internal.h b/stand/libsa/geli/geliboot_internal.h index 2af74466179f..2318690297f8 100644 --- a/stand/libsa/geli/geliboot_internal.h +++ b/stand/libsa/geli/geliboot_internal.h @@ -1,73 +1,73 @@ /*- * Copyright (c) 2015 Allan Jude * Copyright (c) 2005-2011 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _GELIBOOT_INTERNAL_H_ #define _GELIBOOT_INTERNAL_H_ #define _STRING_H_ #define _STRINGS_H_ #define _STDIO_H_ #include #include #include #include #include /* Pull in the md5, sha256, and sha512 implementations */ #include #include #include /* Pull in AES implementation */ #include /* AES-XTS implementation */ #define _STAND 1 #define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */ #include #include "geliboot.h" #define GELIDEV_NAMELEN 32 struct geli_dev { off_t part_end; struct g_eli_softc sc; struct g_eli_metadata md; int keybuf_slot; char *name; /* for prompting; it ends in ':' */ }; int geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize, - const u_char *key, size_t keysize, u_char *iv); + const u_char *key, size_t keysize, u_char *iv, size_t ivlen); #endif /* _GELIBOOT_INTERNAL_H_ */ diff --git a/sys/opencrypto/xform_aes_xts.c b/sys/opencrypto/xform_aes_xts.c index 7a79d4685d21..9894158c0b79 100644 --- a/sys/opencrypto/xform_aes_xts.c +++ b/sys/opencrypto/xform_aes_xts.c @@ -1,160 +1,162 @@ /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr), * Niels Provos (provos@physnet.uni-hamburg.de) and * Damien Miller (djm@mindrot.org). * * This code was written by John Ioannidis for BSD/OS in Athens, Greece, * in November 1995. * * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, * by Angelos D. Keromytis. * * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis * and Niels Provos. * * Additional features in 1999 by Angelos D. Keromytis. * * AES XTS implementation in 2008 by Damien Miller * * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, * Angelos D. Keromytis and Niels Provos. * * Copyright (C) 2001, Angelos D. Keromytis. * * Copyright (C) 2008, Damien Miller * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by John-Mark Gurney * under sponsorship of the FreeBSD Foundation and * Rubicon Communications, LLC (Netgate). * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * You may use this code under the GNU public license if you so wish. Please * contribute changes back to the authors under this freer than GPL license * so that we may further the use of strong encryption without limitations to * all. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ #include __FBSDID("$FreeBSD$"); #include #include static int aes_xts_setkey(void *, const uint8_t *, int); static void aes_xts_encrypt(void *, const uint8_t *, uint8_t *); static void aes_xts_decrypt(void *, const uint8_t *, uint8_t *); static void aes_xts_reinit(void *, const uint8_t *, size_t); /* Encryption instances */ const struct enc_xform enc_xform_aes_xts = { .type = CRYPTO_AES_XTS, .name = "AES-XTS", .ctxsize = sizeof(struct aes_xts_ctx), .blocksize = AES_BLOCK_LEN, .ivsize = AES_XTS_IV_LEN, .minkey = AES_XTS_MIN_KEY, .maxkey = AES_XTS_MAX_KEY, .encrypt = aes_xts_encrypt, .decrypt = aes_xts_decrypt, .setkey = aes_xts_setkey, .reinit = aes_xts_reinit }; /* * Encryption wrapper routines. */ static void aes_xts_reinit(void *key, const uint8_t *iv, size_t ivlen) { struct aes_xts_ctx *ctx = key; uint64_t blocknum; u_int i; +#ifndef _STANDALONE KASSERT(ivlen == sizeof(blocknum), ("%s: invalid IV length", __func__)); +#endif /* * Prepare tweak as E_k2(IV). IV is specified as LE representation * of a 64-bit block number which we allow to be passed in directly. */ bcopy(iv, &blocknum, AES_XTS_IVSIZE); for (i = 0; i < AES_XTS_IVSIZE; i++) { ctx->tweak[i] = blocknum & 0xff; blocknum >>= 8; } /* Last 64 bits of IV are always zero */ bzero(ctx->tweak + AES_XTS_IVSIZE, AES_XTS_IVSIZE); rijndael_encrypt(&ctx->key2, ctx->tweak, ctx->tweak); } static void aes_xts_crypt(struct aes_xts_ctx *ctx, const uint8_t *in, uint8_t *out, u_int do_encrypt) { uint8_t block[AES_XTS_BLOCKSIZE]; u_int i, carry_in, carry_out; for (i = 0; i < AES_XTS_BLOCKSIZE; i++) block[i] = in[i] ^ ctx->tweak[i]; if (do_encrypt) rijndael_encrypt(&ctx->key1, block, out); else rijndael_decrypt(&ctx->key1, block, out); for (i = 0; i < AES_XTS_BLOCKSIZE; i++) out[i] ^= ctx->tweak[i]; /* Exponentiate tweak */ carry_in = 0; for (i = 0; i < AES_XTS_BLOCKSIZE; i++) { carry_out = ctx->tweak[i] & 0x80; ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0); carry_in = carry_out; } if (carry_in) ctx->tweak[0] ^= AES_XTS_ALPHA; explicit_bzero(block, sizeof(block)); } static void aes_xts_encrypt(void *key, const uint8_t *in, uint8_t *out) { aes_xts_crypt(key, in, out, 1); } static void aes_xts_decrypt(void *key, const uint8_t *in, uint8_t *out) { aes_xts_crypt(key, in, out, 0); } static int aes_xts_setkey(void *sched, const uint8_t *key, int len) { struct aes_xts_ctx *ctx; if (len != 32 && len != 64) return (EINVAL); ctx = sched; rijndael_set_key(&ctx->key1, key, len * 4); rijndael_set_key(&ctx->key2, key + (len / 2), len * 4); return (0); }