xref: /freebsd/stand/libsa/geli/geliboot.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
162bd02ceSWarner Losh /*-
262bd02ceSWarner Losh  * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
362bd02ceSWarner Losh  * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
462bd02ceSWarner Losh  * All rights reserved.
562bd02ceSWarner Losh  *
662bd02ceSWarner Losh  * Redistribution and use in source and binary forms, with or without
762bd02ceSWarner Losh  * modification, are permitted provided that the following conditions
862bd02ceSWarner Losh  * are met:
962bd02ceSWarner Losh  * 1. Redistributions of source code must retain the above copyright
1062bd02ceSWarner Losh  *    notice, this list of conditions and the following disclaimer.
1162bd02ceSWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
1262bd02ceSWarner Losh  *    notice, this list of conditions and the following disclaimer in the
1362bd02ceSWarner Losh  *    documentation and/or other materials provided with the distribution.
1462bd02ceSWarner Losh  *
1562bd02ceSWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1662bd02ceSWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1762bd02ceSWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1862bd02ceSWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1962bd02ceSWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2062bd02ceSWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2162bd02ceSWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2262bd02ceSWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2362bd02ceSWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2462bd02ceSWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2562bd02ceSWarner Losh  * SUCH DAMAGE.
2662bd02ceSWarner Losh  */
2762bd02ceSWarner Losh 
28c1418270SIan Lepore #include <stand.h>
29c1418270SIan Lepore #include <stdarg.h>
3062bd02ceSWarner Losh #include "geliboot.h"
31c1418270SIan Lepore #include "geliboot_internal.h"
3262bd02ceSWarner Losh 
33c1418270SIan Lepore struct known_dev {
34c1418270SIan Lepore 	char			name[GELIDEV_NAMELEN];
35c1418270SIan Lepore 	struct geli_dev 	*gdev;
36c1418270SIan Lepore 	SLIST_ENTRY(known_dev)	entries;
37c1418270SIan Lepore };
3862bd02ceSWarner Losh 
39c1418270SIan Lepore SLIST_HEAD(known_dev_list, known_dev) known_devs_head =
40c1418270SIan Lepore     SLIST_HEAD_INITIALIZER(known_devs_head);
4162bd02ceSWarner Losh 
4262bd02ceSWarner Losh static geli_ukey saved_keys[GELI_MAX_KEYS];
4362bd02ceSWarner Losh static unsigned int nsaved_keys = 0;
4462bd02ceSWarner Losh 
4562bd02ceSWarner Losh /*
4662bd02ceSWarner Losh  * Copy keys from local storage to the keybuf struct.
4762bd02ceSWarner Losh  * Destroy the local storage when finished.
4862bd02ceSWarner Losh  */
4962bd02ceSWarner Losh void
geli_export_key_buffer(struct keybuf * fkeybuf)50c1418270SIan Lepore geli_export_key_buffer(struct keybuf *fkeybuf)
5162bd02ceSWarner Losh {
5262bd02ceSWarner Losh 	unsigned int i;
5362bd02ceSWarner Losh 
5462bd02ceSWarner Losh 	for (i = 0; i < nsaved_keys; i++) {
5562bd02ceSWarner Losh 		fkeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_GELI;
5662bd02ceSWarner Losh 		memcpy(fkeybuf->kb_ents[i].ke_data, saved_keys[i],
5762bd02ceSWarner Losh 		    G_ELI_USERKEYLEN);
5862bd02ceSWarner Losh 	}
5962bd02ceSWarner Losh 	fkeybuf->kb_nents = nsaved_keys;
6062bd02ceSWarner Losh 	explicit_bzero(saved_keys, sizeof(saved_keys));
6162bd02ceSWarner Losh }
6262bd02ceSWarner Losh 
6362bd02ceSWarner Losh /*
6462bd02ceSWarner Losh  * Copy keys from a keybuf struct into local storage.
6562bd02ceSWarner Losh  * Zero out the keybuf.
6662bd02ceSWarner Losh  */
6762bd02ceSWarner Losh void
geli_import_key_buffer(struct keybuf * skeybuf)68c1418270SIan Lepore geli_import_key_buffer(struct keybuf *skeybuf)
6962bd02ceSWarner Losh {
7062bd02ceSWarner Losh 	unsigned int i;
7162bd02ceSWarner Losh 
7262bd02ceSWarner Losh 	for (i = 0; i < skeybuf->kb_nents && i < GELI_MAX_KEYS; i++) {
7362bd02ceSWarner Losh 		memcpy(saved_keys[i], skeybuf->kb_ents[i].ke_data,
7462bd02ceSWarner Losh 		    G_ELI_USERKEYLEN);
7562bd02ceSWarner Losh 		explicit_bzero(skeybuf->kb_ents[i].ke_data,
7662bd02ceSWarner Losh 		    G_ELI_USERKEYLEN);
7762bd02ceSWarner Losh 		skeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE;
7862bd02ceSWarner Losh 	}
7962bd02ceSWarner Losh 	nsaved_keys = skeybuf->kb_nents;
8062bd02ceSWarner Losh 	skeybuf->kb_nents = 0;
8162bd02ceSWarner Losh }
8262bd02ceSWarner Losh 
83c1418270SIan Lepore void
geli_add_key(geli_ukey key)84c1418270SIan Lepore geli_add_key(geli_ukey key)
8562bd02ceSWarner Losh {
8662bd02ceSWarner Losh 
8762bd02ceSWarner Losh 	/*
8862bd02ceSWarner Losh 	 * If we run out of key space, the worst that will happen is
8962bd02ceSWarner Losh 	 * it will ask the user for the password again.
9062bd02ceSWarner Losh 	 */
9162bd02ceSWarner Losh 	if (nsaved_keys < GELI_MAX_KEYS) {
9262bd02ceSWarner Losh 		memcpy(saved_keys[nsaved_keys], key, G_ELI_USERKEYLEN);
9362bd02ceSWarner Losh 		nsaved_keys++;
9462bd02ceSWarner Losh 	}
9562bd02ceSWarner Losh }
9662bd02ceSWarner Losh 
9762bd02ceSWarner Losh static int
geli_findkey(struct geli_dev * gdev,u_char * mkey)98c1418270SIan Lepore geli_findkey(struct geli_dev *gdev, u_char *mkey)
9962bd02ceSWarner Losh {
10062bd02ceSWarner Losh 	u_int keynum;
10162bd02ceSWarner Losh 	int i;
10262bd02ceSWarner Losh 
103c1418270SIan Lepore 	if (gdev->keybuf_slot >= 0) {
104c1418270SIan Lepore 		if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[gdev->keybuf_slot],
10562bd02ceSWarner Losh 		    mkey, &keynum) == 0) {
10662bd02ceSWarner Losh 			return (0);
10762bd02ceSWarner Losh 		}
10862bd02ceSWarner Losh 	}
10962bd02ceSWarner Losh 
11062bd02ceSWarner Losh 	for (i = 0; i < nsaved_keys; i++) {
111c1418270SIan Lepore 		if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[i], mkey,
11262bd02ceSWarner Losh 		    &keynum) == 0) {
113c1418270SIan Lepore 			gdev->keybuf_slot = i;
11462bd02ceSWarner Losh 			return (0);
11562bd02ceSWarner Losh 		}
11662bd02ceSWarner Losh 	}
11762bd02ceSWarner Losh 
11862bd02ceSWarner Losh 	return (1);
11962bd02ceSWarner Losh }
12062bd02ceSWarner Losh 
12162bd02ceSWarner Losh /*
122c1418270SIan Lepore  * Read the last sector of a drive or partition and see if it is GELI encrypted.
12362bd02ceSWarner Losh  */
124c1418270SIan Lepore struct geli_dev *
geli_taste(geli_readfunc readfunc,void * readpriv,daddr_t lastsector,const char * namefmt,...)125c1418270SIan Lepore geli_taste(geli_readfunc readfunc, void *readpriv, daddr_t lastsector,
126c1418270SIan Lepore     const char *namefmt, ...)
12762bd02ceSWarner Losh {
128c1418270SIan Lepore 	va_list args;
12962bd02ceSWarner Losh 	struct g_eli_metadata md;
130c1418270SIan Lepore 	struct known_dev *kdev;
131c1418270SIan Lepore 	struct geli_dev *gdev;
132c1418270SIan Lepore 	u_char *buf;
133c1418270SIan Lepore 	char devname[GELIDEV_NAMELEN];
13462bd02ceSWarner Losh 	int error;
13562bd02ceSWarner Losh 	off_t alignsector;
13662bd02ceSWarner Losh 
137c1418270SIan Lepore 	/*
138c1418270SIan Lepore 	 * Format the name into a temp buffer and use that to search for an
139c1418270SIan Lepore 	 * existing known_dev instance.  If not found, this has the side effect
140c1418270SIan Lepore 	 * of initializing kdev to NULL.
141c1418270SIan Lepore 	 */
142c1418270SIan Lepore 	va_start(args, namefmt);
143c1418270SIan Lepore 	vsnprintf(devname, sizeof(devname), namefmt, args);
144c1418270SIan Lepore 	va_end(args);
145c1418270SIan Lepore 	SLIST_FOREACH(kdev, &known_devs_head, entries) {
146c1418270SIan Lepore 		if (strcmp(kdev->name, devname) == 0)
147c1418270SIan Lepore 			return (kdev->gdev);
148c1418270SIan Lepore 	}
149c1418270SIan Lepore 
150c1418270SIan Lepore         /* Determine whether the new device is geli-encrypted... */
151c1418270SIan Lepore 	if ((buf = malloc(DEV_GELIBOOT_BSIZE)) == NULL)
152c1418270SIan Lepore 		goto out;
15362bd02ceSWarner Losh 	alignsector = rounddown2(lastsector * DEV_BSIZE, DEV_GELIBOOT_BSIZE);
15462bd02ceSWarner Losh 	if (alignsector + DEV_GELIBOOT_BSIZE > ((lastsector + 1) * DEV_BSIZE)) {
15562bd02ceSWarner Losh 		/* Don't read past the end of the disk */
156c1418270SIan Lepore 		alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE -
157c1418270SIan Lepore 		    DEV_GELIBOOT_BSIZE;
15862bd02ceSWarner Losh 	}
159c1418270SIan Lepore 	error = readfunc(NULL, readpriv, alignsector, buf, DEV_GELIBOOT_BSIZE);
16062bd02ceSWarner Losh 	if (error != 0) {
161c1418270SIan Lepore 		goto out;
16262bd02ceSWarner Losh 	}
163c1418270SIan Lepore 
164c1418270SIan Lepore 	/*
165c1418270SIan Lepore 	 * We have a new known_device.  Whether it's geli-encrypted or not,
166*9cd75b55SGordon Bergling 	 * record its existence so we can avoid doing IO to probe it next time.
167c1418270SIan Lepore 	 */
168c1418270SIan Lepore 	if ((kdev = malloc(sizeof(*kdev))) == NULL)
169c1418270SIan Lepore 		goto out;
170c1418270SIan Lepore 	strlcpy(kdev->name, devname, sizeof(kdev->name));
171c1418270SIan Lepore 	kdev->gdev = NULL;
172c1418270SIan Lepore 	SLIST_INSERT_HEAD(&known_devs_head, kdev, entries);
173c1418270SIan Lepore 
17462bd02ceSWarner Losh 	/* Extract the last 4k sector of the disk. */
17562bd02ceSWarner Losh 	error = eli_metadata_decode(buf, &md);
17662bd02ceSWarner Losh 	if (error != 0) {
17762bd02ceSWarner Losh 		/* Try the last 512 byte sector instead. */
17862bd02ceSWarner Losh 		error = eli_metadata_decode(buf +
17962bd02ceSWarner Losh 		    (DEV_GELIBOOT_BSIZE - DEV_BSIZE), &md);
18062bd02ceSWarner Losh 		if (error != 0) {
181c1418270SIan Lepore 			goto out;
18262bd02ceSWarner Losh 		}
18362bd02ceSWarner Losh 	}
18462bd02ceSWarner Losh 
18562bd02ceSWarner Losh 	if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
18662bd02ceSWarner Losh 		/* The GELIBOOT feature is not activated */
187c1418270SIan Lepore 		goto out;
18862bd02ceSWarner Losh 	}
18962bd02ceSWarner Losh 	if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
19062bd02ceSWarner Losh 		/* Swap device, skip it. */
191c1418270SIan Lepore 		goto out;
19262bd02ceSWarner Losh 	}
19362bd02ceSWarner Losh 
19462bd02ceSWarner Losh 	/*
195c1418270SIan Lepore 	 * It's geli-encrypted, create a geli_dev for it and link it into the
196c1418270SIan Lepore 	 * known_dev instance.
197c1418270SIan Lepore 	 */
198c1418270SIan Lepore 	gdev = malloc(sizeof(struct geli_dev));
199c1418270SIan Lepore 	if (gdev == NULL)
200c1418270SIan Lepore 		goto out;
201c1418270SIan Lepore 	gdev->part_end = lastsector;
202c1418270SIan Lepore 	gdev->keybuf_slot = -1;
203c1418270SIan Lepore 	gdev->md = md;
204c1418270SIan Lepore 	gdev->name = kdev->name;
205c1418270SIan Lepore 	eli_metadata_softc(&gdev->sc, &md, DEV_BSIZE,
206c1418270SIan Lepore 	    (lastsector + DEV_BSIZE) * DEV_BSIZE);
207c1418270SIan Lepore 	kdev->gdev = gdev;
208c1418270SIan Lepore out:
209c1418270SIan Lepore 	free(buf);
210c1418270SIan Lepore 	if (kdev == NULL)
211c1418270SIan Lepore 		return (NULL);
212c1418270SIan Lepore 	return (kdev->gdev);
213c1418270SIan Lepore }
214c1418270SIan Lepore 
215c1418270SIan Lepore /*
216c1418270SIan Lepore  * Attempt to decrypt the device.  This will try existing keys first, then will
217c1418270SIan Lepore  * prompt for a passphrase if there are no existing keys that work.
21862bd02ceSWarner Losh  */
21962bd02ceSWarner Losh static int
geli_probe(struct geli_dev * gdev,const char * passphrase,u_char * mkeyp)220c1418270SIan Lepore geli_probe(struct geli_dev *gdev, const char *passphrase, u_char *mkeyp)
22162bd02ceSWarner Losh {
22262bd02ceSWarner Losh 	u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
22362bd02ceSWarner Losh 	u_int keynum;
22462bd02ceSWarner Losh 	struct hmac_ctx ctx;
22562bd02ceSWarner Losh 	int error;
22662bd02ceSWarner Losh 
22762bd02ceSWarner Losh 	if (mkeyp != NULL) {
22862bd02ceSWarner Losh 		memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN);
22962bd02ceSWarner Losh 		explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN);
230c1418270SIan Lepore 		goto found_key;
23162bd02ceSWarner Losh 	}
23262bd02ceSWarner Losh 
233c1418270SIan Lepore 	if (geli_findkey(gdev, mkey) == 0) {
23462bd02ceSWarner Losh 		goto found_key;
23562bd02ceSWarner Losh 	}
23662bd02ceSWarner Losh 
23762bd02ceSWarner Losh 	g_eli_crypto_hmac_init(&ctx, NULL, 0);
23862bd02ceSWarner Losh 	/*
23962bd02ceSWarner Losh 	 * Prepare Derived-Key from the user passphrase.
24062bd02ceSWarner Losh 	 */
241c1418270SIan Lepore 	if (gdev->md.md_iterations < 0) {
24262bd02ceSWarner Losh 		/* XXX TODO: Support loading key files. */
24362bd02ceSWarner Losh 		return (1);
244c1418270SIan Lepore 	} else if (gdev->md.md_iterations == 0) {
245c1418270SIan Lepore 		g_eli_crypto_hmac_update(&ctx, gdev->md.md_salt,
246c1418270SIan Lepore 		    sizeof(gdev->md.md_salt));
24762bd02ceSWarner Losh 		g_eli_crypto_hmac_update(&ctx, (const uint8_t *)passphrase,
24862bd02ceSWarner Losh 		    strlen(passphrase));
249c1418270SIan Lepore 	} else if (gdev->md.md_iterations > 0) {
250c1418270SIan Lepore 		printf("Calculating GELI Decryption Key for %s %d"
251c1418270SIan Lepore 		    " iterations...\n", gdev->name, gdev->md.md_iterations);
25262bd02ceSWarner Losh 		u_char dkey[G_ELI_USERKEYLEN];
25362bd02ceSWarner Losh 
254c1418270SIan Lepore 		pkcs5v2_genkey(dkey, sizeof(dkey), gdev->md.md_salt,
255c1418270SIan Lepore 		    sizeof(gdev->md.md_salt), passphrase,
256c1418270SIan Lepore 		    gdev->md.md_iterations);
25762bd02ceSWarner Losh 		g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
25862bd02ceSWarner Losh 		explicit_bzero(dkey, sizeof(dkey));
25962bd02ceSWarner Losh 	}
26062bd02ceSWarner Losh 
26162bd02ceSWarner Losh 	g_eli_crypto_hmac_final(&ctx, key, 0);
26262bd02ceSWarner Losh 
263c1418270SIan Lepore 	error = g_eli_mkey_decrypt_any(&gdev->md, key, mkey, &keynum);
26462bd02ceSWarner Losh 	if (error == -1) {
26562bd02ceSWarner Losh 		explicit_bzero(mkey, sizeof(mkey));
26662bd02ceSWarner Losh 		explicit_bzero(key, sizeof(key));
26762bd02ceSWarner Losh 		printf("Bad GELI key: bad password?\n");
26862bd02ceSWarner Losh 		return (error);
26962bd02ceSWarner Losh 	} else if (error != 0) {
27062bd02ceSWarner Losh 		explicit_bzero(mkey, sizeof(mkey));
27162bd02ceSWarner Losh 		explicit_bzero(key, sizeof(key));
27262bd02ceSWarner Losh 		printf("Failed to decrypt GELI master key: %d\n", error);
27362bd02ceSWarner Losh 		return (error);
27462bd02ceSWarner Losh 	} else {
27562bd02ceSWarner Losh 		/* Add key to keychain */
276c1418270SIan Lepore 		geli_add_key(key);
27762bd02ceSWarner Losh 		explicit_bzero(&key, sizeof(key));
27862bd02ceSWarner Losh 	}
27962bd02ceSWarner Losh 
28062bd02ceSWarner Losh found_key:
28162bd02ceSWarner Losh 	/* Store the keys */
282c1418270SIan Lepore 	bcopy(mkey, gdev->sc.sc_mkey, sizeof(gdev->sc.sc_mkey));
283c1418270SIan Lepore 	bcopy(mkey, gdev->sc.sc_ivkey, sizeof(gdev->sc.sc_ivkey));
284c1418270SIan Lepore 	mkp = mkey + sizeof(gdev->sc.sc_ivkey);
285c1418270SIan Lepore 	if ((gdev->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
286c1418270SIan Lepore 		bcopy(mkp, gdev->sc.sc_ekey, G_ELI_DATAKEYLEN);
28762bd02ceSWarner Losh 	} else {
28862bd02ceSWarner Losh 		/*
28962bd02ceSWarner Losh 		 * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
29062bd02ceSWarner Losh 		 */
29162bd02ceSWarner Losh 		g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x10", 1,
292c1418270SIan Lepore 		    gdev->sc.sc_ekey, 0);
29362bd02ceSWarner Losh 	}
29462bd02ceSWarner Losh 	explicit_bzero(mkey, sizeof(mkey));
29562bd02ceSWarner Losh 
29662bd02ceSWarner Losh 	/* Initialize the per-sector IV. */
297c1418270SIan Lepore 	switch (gdev->sc.sc_ealgo) {
29862bd02ceSWarner Losh 	case CRYPTO_AES_XTS:
29962bd02ceSWarner Losh 		break;
30062bd02ceSWarner Losh 	default:
301c1418270SIan Lepore 		SHA256_Init(&gdev->sc.sc_ivctx);
302c1418270SIan Lepore 		SHA256_Update(&gdev->sc.sc_ivctx, gdev->sc.sc_ivkey,
303c1418270SIan Lepore 		    sizeof(gdev->sc.sc_ivkey));
30462bd02ceSWarner Losh 		break;
30562bd02ceSWarner Losh 	}
30662bd02ceSWarner Losh 
30762bd02ceSWarner Losh 	return (0);
30862bd02ceSWarner Losh }
30962bd02ceSWarner Losh 
31062bd02ceSWarner Losh int
geli_io(struct geli_dev * gdev,geli_op_t enc,off_t offset,u_char * buf,size_t bytes)311de776da3SToomas Soome geli_io(struct geli_dev *gdev, geli_op_t enc, off_t offset, u_char *buf,
312de776da3SToomas Soome     size_t bytes)
31362bd02ceSWarner Losh {
31462bd02ceSWarner Losh 	u_char iv[G_ELI_IVKEYLEN];
31562bd02ceSWarner Losh 	u_char *pbuf;
31662bd02ceSWarner Losh 	int error;
31762bd02ceSWarner Losh 	off_t dstoff;
31862bd02ceSWarner Losh 	uint64_t keyno;
31962bd02ceSWarner Losh 	size_t n, nsec, secsize;
32062bd02ceSWarner Losh 	struct g_eli_key gkey;
32162bd02ceSWarner Losh 
32262bd02ceSWarner Losh 	pbuf = buf;
32362bd02ceSWarner Losh 
324c1418270SIan Lepore 	secsize = gdev->sc.sc_sectorsize;
32562bd02ceSWarner Losh 	nsec = bytes / secsize;
32662bd02ceSWarner Losh 	if (nsec == 0) {
32762bd02ceSWarner Losh 		/*
32862bd02ceSWarner Losh 		 * A read of less than the GELI sector size has been
32962bd02ceSWarner Losh 		 * requested. The caller provided destination buffer may
33062bd02ceSWarner Losh 		 * not be big enough to boost the read to a full sector,
33162bd02ceSWarner Losh 		 * so just attempt to decrypt the truncated sector.
33262bd02ceSWarner Losh 		 */
33362bd02ceSWarner Losh 		secsize = bytes;
33462bd02ceSWarner Losh 		nsec = 1;
33562bd02ceSWarner Losh 	}
33662bd02ceSWarner Losh 
33762bd02ceSWarner Losh 	for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) {
33862bd02ceSWarner Losh 
339c1418270SIan Lepore 		g_eli_crypto_ivgen(&gdev->sc, dstoff, iv, G_ELI_IVKEYLEN);
34062bd02ceSWarner Losh 
34162bd02ceSWarner Losh 		/* Get the key that corresponds to this offset. */
34262bd02ceSWarner Losh 		keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize;
343c1418270SIan Lepore 		g_eli_key_fill(&gdev->sc, &gkey, keyno);
34462bd02ceSWarner Losh 
345de776da3SToomas Soome 		error = geliboot_crypt(gdev->sc.sc_ealgo, enc, pbuf, secsize,
346c7721958SJohn Baldwin 		    gkey.gek_key, gdev->sc.sc_ekeylen, iv);
34762bd02ceSWarner Losh 
34862bd02ceSWarner Losh 		if (error != 0) {
34962bd02ceSWarner Losh 			explicit_bzero(&gkey, sizeof(gkey));
350de776da3SToomas Soome 			printf("%s: Failed to %s!", __func__,
351de776da3SToomas Soome 			    enc ? "encrypt" : "decrypt");
35262bd02ceSWarner Losh 			return (error);
35362bd02ceSWarner Losh 		}
35462bd02ceSWarner Losh 		pbuf += secsize;
35562bd02ceSWarner Losh 	}
35662bd02ceSWarner Losh 	explicit_bzero(&gkey, sizeof(gkey));
35762bd02ceSWarner Losh 	return (0);
35862bd02ceSWarner Losh }
35962bd02ceSWarner Losh 
36062bd02ceSWarner Losh int
geli_havekey(struct geli_dev * gdev)361c1418270SIan Lepore geli_havekey(struct geli_dev *gdev)
36262bd02ceSWarner Losh {
36362bd02ceSWarner Losh 	u_char mkey[G_ELI_DATAIVKEYLEN];
364c1418270SIan Lepore 	int err;
36562bd02ceSWarner Losh 
366c1418270SIan Lepore 	err = ENOENT;
367c1418270SIan Lepore 	if (geli_findkey(gdev, mkey) == 0) {
368c1418270SIan Lepore 		if (geli_probe(gdev, NULL, mkey) == 0)
369c1418270SIan Lepore 			err = 0;
37062bd02ceSWarner Losh 		explicit_bzero(mkey, sizeof(mkey));
371c1418270SIan Lepore 	}
372c1418270SIan Lepore 	return (err);
37362bd02ceSWarner Losh }
37462bd02ceSWarner Losh 
37562bd02ceSWarner Losh int
geli_passphrase(struct geli_dev * gdev,char * pw)376c1418270SIan Lepore geli_passphrase(struct geli_dev *gdev, char *pw)
37762bd02ceSWarner Losh {
37862bd02ceSWarner Losh 	int i;
37962bd02ceSWarner Losh 
38062bd02ceSWarner Losh 	/* TODO: Implement GELI keyfile(s) support */
38162bd02ceSWarner Losh 	for (i = 0; i < 3; i++) {
38262bd02ceSWarner Losh 		/* Try cached passphrase */
38362bd02ceSWarner Losh 		if (i == 0 && pw[0] != '\0') {
384c1418270SIan Lepore 			if (geli_probe(gdev, pw, NULL) == 0) {
38562bd02ceSWarner Losh 				return (0);
38662bd02ceSWarner Losh 			}
38762bd02ceSWarner Losh 		}
388c1418270SIan Lepore 		printf("GELI Passphrase for %s ", gdev->name);
38962bd02ceSWarner Losh 		pwgets(pw, GELI_PW_MAXLEN,
390c1418270SIan Lepore 		    (gdev->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0);
39162bd02ceSWarner Losh 		printf("\n");
392c1418270SIan Lepore 		if (geli_probe(gdev, pw, NULL) == 0) {
39362bd02ceSWarner Losh 			return (0);
39462bd02ceSWarner Losh 		}
39562bd02ceSWarner Losh 	}
39662bd02ceSWarner Losh 
39762bd02ceSWarner Losh 	return (1);
39862bd02ceSWarner Losh }
399