diff --git a/discover/device-handler.c b/discover/device-handler.c
index e75f4123..7935a2b8 100644
--- a/discover/device-handler.c
+++ b/discover/device-handler.c
@@ -60,6 +60,13 @@ struct progress_info {
 	struct list_item	list;
 };
 
+struct crypt_info {
+	struct discover_device	*source_device;
+	char			*dm_name;
+
+	struct list_item	list;
+};
+
 struct device_handler {
 	struct discover_server	*server;
 	int			dry_run;
@@ -95,6 +102,8 @@ struct device_handler {
 	struct plugin_option	**plugins;
 	unsigned int		n_plugins;
 	bool			plugin_installing;
+
+	struct list		crypt_devices;
 };
 
 static int mount_device(struct discover_device *dev);
@@ -265,9 +274,30 @@ void device_handler_destroy(struct device_handler *handler)
 static int destroy_device(void *arg)
 {
 	struct discover_device *dev = arg;
+	struct process *p;
 
 	umount_device(dev);
 
+	devmapper_destroy_snapshot(dev);
+
+	if (dev->crypt_device) {
+		const char *argv[] = {
+			pb_system_apps.cryptsetup,
+			"luksClose",
+			dev->device->id,
+			NULL
+		};
+
+		p = process_create(dev);
+		p->path = pb_system_apps.cryptsetup;
+		p->argv = argv;
+
+		if (process_run_async(p)) {
+			pb_log("Failed to run cryptsetup\n");
+			return -1;
+		}
+	}
+
 	return 0;
 }
 
@@ -376,6 +406,7 @@ struct device_handler *device_handler_init(struct discover_server *server,
 	list_init(&handler->unresolved_boot_options);
 
 	list_init(&handler->progress);
+	list_init(&handler->crypt_devices);
 
 	/* set up our mount point base */
 	pb_mkdir_recursive(mount_base());
@@ -399,6 +430,7 @@ struct device_handler *device_handler_init(struct discover_server *server,
 void device_handler_reinit(struct device_handler *handler)
 {
 	struct discover_boot_option *opt, *tmp;
+	struct crypt_info *crypt, *c;
 	struct ramdisk_device *ramdisk;
 	struct config *config;
 	unsigned int i;
@@ -449,6 +481,11 @@ void device_handler_reinit(struct device_handler *handler)
 
 	discover_server_notify_plugins_remove(handler->server);
 
+	/* forget encrypted devices */
+	list_for_each_entry_safe(&handler->crypt_devices, crypt, c, list)
+		talloc_free(crypt);
+	list_init(&handler->crypt_devices);
+
 	set_env_variables(config_get());
 
 	/* If the safe mode warning was active disable it now */
@@ -1230,6 +1267,102 @@ void device_handler_release_ramdisk(struct discover_device *device)
 	device->ramdisk = NULL;
 }
 
+/*
+ * Check if a device name matches the name of an encrypted device that has been
+ * opened. If it matches remove it from the list and remove the original crypt
+ * discover device.
+ */
+bool device_handler_found_crypt_device(struct device_handler *handler,
+		const char *name)
+{
+	struct crypt_info *crypt, *c;
+
+	list_for_each_entry_safe(&handler->crypt_devices, crypt, c, list) {
+		if (!strncmp(crypt->dm_name, name, strlen(crypt->dm_name))) {
+			device_handler_remove(handler, crypt->source_device);
+			list_remove(&crypt->list);
+			talloc_free(crypt);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static void cryptsetup_cb(struct process *process)
+{
+	struct device_handler *handler = process->data;
+
+	if (process->exit_status) {
+		/* failed to open the device; stop tracking it */
+		device_handler_found_crypt_device(handler, process->argv[3]);
+		device_handler_status_err(handler,
+				_("Failed to open encrypted device %s"),
+				process->argv[2]);
+	}
+}
+
+void device_handler_open_encrypted_dev(struct device_handler *handler,
+		char *password, char *device_id)
+{
+	struct discover_device *dev;
+	struct crypt_info *crypt;
+	const char *device_path;
+	struct process *p;
+	char *name;
+	int result;
+
+	dev = device_lookup_by_id(handler, device_id);
+	if (!dev) {
+		pb_log_fn("Can't find device %s\n", device_id);
+		device_handler_status_err(handler,
+				_("Encrypted device %s does not exist"),
+				device_id);
+		return;
+	}
+
+	device_path = dev->device_path;
+	name = talloc_asprintf(handler, "luks_%s", device_id);
+
+	const char *argv[] = {
+		pb_system_apps.cryptsetup,
+		"luksOpen",
+		device_path,
+		name,
+		"-",
+		NULL
+	};
+
+	p = process_create(handler);
+	p->path = pb_system_apps.cryptsetup;
+	p->argv = argv;
+	p->exit_cb = cryptsetup_cb;
+	p->keep_stdout = true;
+	p->pipe_stdin = talloc_asprintf(p, "%s\n", password);
+
+	result = process_run_async(p);
+	if (result) {
+		pb_log("Failed to run cryptsetup\n");
+		return;
+	}
+
+	crypt = talloc(handler, struct crypt_info);
+	crypt->source_device = dev;
+	crypt->dm_name = name;
+	list_add(&handler->crypt_devices, &crypt->list);
+}
+
+void device_handler_add_encrypted_dev(struct device_handler *handler,
+		struct discover_device *dev)
+{
+	system_info_register_blockdev(dev->device->id, dev->uuid, "");
+	discover_server_notify_device_add(handler->server,
+					  dev->device);
+	dev->notified = true;
+	if (!device_lookup_by_uuid(handler, dev->uuid))
+		device_handler_add_device(handler, dev);
+}
+
 /* Start discovery on a hotplugged device. The device will be in our devices
  * array, but has only just been initialised by the hotplug source.
  */
@@ -2121,7 +2254,6 @@ static int umount_device(struct discover_device *dev)
 		return -1;
 
 	dev->mounted = false;
-	devmapper_destroy_snapshot(dev);
 
 	pb_rmdir_recursive(mount_base(), dev->mount_path);
 
diff --git a/discover/device-handler.h b/discover/device-handler.h
index 9619a2df..65911208 100644
--- a/discover/device-handler.h
+++ b/discover/device-handler.h
@@ -33,6 +33,7 @@ struct discover_device {
 	bool			mounted;
 	bool			mounted_rw;
 	bool			unmount;
+	bool			crypt_device;
 
 	bool			notified;
 
@@ -89,6 +90,9 @@ const struct plugin_option *device_handler_get_plugin(
 struct network *device_handler_get_network(
 		const struct device_handler *handler);
 
+bool device_handler_found_crypt_device(struct device_handler *handler,
+		const char *name);
+
 struct discover_device *discover_device_create(struct device_handler *handler,
 		const char *uuid, const char *id);
 void device_handler_add_device(struct device_handler *handler,
@@ -98,6 +102,10 @@ void device_handler_add_ramdisk(struct device_handler *handler,
 struct ramdisk_device *device_handler_get_ramdisk(
 		struct device_handler *handler);
 void device_handler_release_ramdisk(struct discover_device *device);
+void device_handler_open_encrypted_dev(struct device_handler *handler,
+		char *password, char *device_id);
+void device_handler_add_encrypted_dev(struct device_handler *handler,
+		struct discover_device *dev);
 int device_handler_discover(struct device_handler *handler,
 		struct discover_device *dev);
 int device_handler_dhcp(struct device_handler *handler,
diff --git a/discover/discover-server.c b/discover/discover-server.c
index 23d6113e..1a332cbf 100644
--- a/discover/discover-server.c
+++ b/discover/discover-server.c
@@ -365,13 +365,29 @@ static int discover_server_handle_auth_message(struct client *client,
 					_("Password updated successfully"));
 		}
 		break;
+	case AUTH_MSG_DECRYPT:
+		if (!client->can_modify) {
+			pb_log("Unauthenticated client tried to open encrypted device %s\n",
+					auth_msg->decrypt_dev.device_id);
+			rc = -1;
+			status->type = STATUS_ERROR;
+			status->message = talloc_asprintf(status,
+					_("Must authenticate before opening encrypted device"));
+			break;
+		}
+
+		device_handler_open_encrypted_dev(client->server->device_handler,
+				auth_msg->decrypt_dev.password,
+				auth_msg->decrypt_dev.device_id);
+		break;
 	default:
 		pb_log("%s: unknown op\n", __func__);
 		rc = -1;
 		break;
 	}
 
-	write_boot_status_message(client->server, client, status);
+	if (status->message)
+		write_boot_status_message(client->server, client, status);
 	talloc_free(status);
 
 	return rc;
diff --git a/discover/udev.c b/discover/udev.c
index fa5d4b41..0c3da66a 100644
--- a/discover/udev.c
+++ b/discover/udev.c
@@ -106,7 +106,7 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev,
 		"swap",
 		NULL,
 	};
-	bool cdrom, usb;
+	bool cdrom, usb, luks = false;
 
 	typestr = udev_device_get_devtype(dev);
 	if (!typestr) {
@@ -142,11 +142,18 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev,
 		}
 	}
 
-	/* Ignore any device mapper devices that aren't logical volumes */
+	/*
+	 * Ignore any device mapper devices that aren't logical volumes or
+	 * opened encrypted devices
+	 */
 	devname = udev_device_get_property_value(dev, "DM_NAME");
-	if (devname && ! udev_device_get_property_value(dev, "DM_LV_NAME")) {
-		pb_debug("SKIP: dm-device %s\n", devname);
-		return 0;
+	if (devname) {
+		if (device_handler_found_crypt_device(udev->handler, devname)) {
+			luks = true;
+		} else if (!udev_device_get_property_value(dev, "DM_LV_NAME")) {
+			pb_debug("SKIP: dm-device %s\n", devname);
+			return 0;
+		}
 	}
 
 	type = udev_device_get_property_value(dev, "ID_FS_TYPE");
@@ -216,16 +223,32 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev,
 	usb = !!udev_device_get_property_value(dev, "ID_USB_DRIVER");
 	if (cdrom)
 		ddev->device->type = DEVICE_TYPE_OPTICAL;
+	else if (strncmp(type, "crypto_LUKS", strlen("crypto_LUKS")) == 0)
+		ddev->device->type = DEVICE_TYPE_LUKS;
 	else
 		ddev->device->type = usb ? DEVICE_TYPE_USB : DEVICE_TYPE_DISK;
 
 	udev_setup_device_params(dev, ddev);
 
+	/*
+	 * Don't perform discovery on encrypted devices, just register and
+	 * notify clients.
+	 */
+	if (ddev->device->type == DEVICE_TYPE_LUKS) {
+		pb_log("Notifying clients about encrypted device %s\n",
+				name);
+		device_handler_add_encrypted_dev(udev->handler, ddev);
+		return 0;
+	}
+
 	/* Create a snapshot for all disk devices */
 	if ((ddev->device->type == DEVICE_TYPE_DISK ||
 	     ddev->device->type == DEVICE_TYPE_USB))
 		devmapper_init_snapshot(udev->handler, ddev);
 
+	/* Note if this is an opened LUKS device */
+	ddev->crypt_device = luks;
+
 	device_handler_discover(udev->handler, ddev);
 
 	return 0;
