diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml
index a46f96a9b..700488c51 100644
--- a/data/org.freedesktop.UDisks2.xml
+++ b/data/org.freedesktop.UDisks2.xml
@@ -2360,6 +2360,19 @@
+
+
+
+
+
+
diff --git a/src/tests/dbus-tests/test_50_block.py b/src/tests/dbus-tests/test_50_block.py
index 82d8a84c8..f210142e5 100644
--- a/src/tests/dbus-tests/test_50_block.py
+++ b/src/tests/dbus-tests/test_50_block.py
@@ -357,6 +357,35 @@ def test_rescan(self):
disk.Rescan(self.no_options, dbus_interface=self.iface_prefix + '.Block')
+ def test_encrypt(self):
+ disk = self.vdevs[0]
+ device = self.get_device(disk)
+ self.assertIsNotNone(device)
+
+ d = dbus.Dictionary(signature='sv')
+ d['passphrase'] = "shouldnotseeme"
+ d['key-size'] = dbus.UInt32(256)
+ d['cipher'] = "aes"
+ d['cipher-mode'] = "cbc-essiv:sha256"
+ d['resilience'] = "datashift" # required, otherwise won't work
+ d['hash'] = "sha256"
+ d['max-hotzone-size'] = dbus.UInt64(0)
+ d['sector-size'] = dbus.UInt32(512)
+ d['new-volume_key'] = True
+
+ device.Encrypt(self.LUKS_PASSPHRASE, d, dbus_interface=self.iface_prefix + '.Block')
+
+ # verify that device now has the .Encrypted interface
+ device = self.get_device(disk)
+ self.assertHasIface(device, "org.freedesktop.UDisks2.Encrypted")
+
+ # verify that the newly encrypted device can be unlocked
+ luks_obj = device.Unlock("shouldnotseeme", self.no_options,
+ dbus_interface=self.iface_prefix + '.Encrypted')
+ self.assertIsNotNone(luks_obj)
+ ret, _ = self.run_command("ls /dev/mapper/luks*")
+ self.assertEqual(ret, 0)
+
class UdisksBlockRemovableTest(udiskstestcase.UdisksTestCase):
'''Extra block device tests over a scsi_debug removable device'''
diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c
index 5b5588b2c..708e855a1 100644
--- a/src/udiskslinuxblock.c
+++ b/src/udiskslinuxblock.c
@@ -4308,6 +4308,129 @@ handle_restore_encrypted_header (UDisksBlock *encrypted,
/* ---------------------------------------------------------------------------------------------------- */
+/* runs in thread dedicated to handling method call */
+static gboolean
+handle_encrypt (UDisksBlock *block,
+ GDBusMethodInvocation *invocation,
+ const gchar *passphrase,
+ GVariant *options)
+{
+ UDisksObject *object = NULL;
+ UDisksDaemon *daemon;
+ UDisksState *state = NULL;
+ uid_t caller_uid;
+ GError *error = NULL;
+ UDisksBaseJob *job = NULL;
+
+ const gchar *device;
+ BDCryptoKeyslotContext *context = NULL;
+ guint32 key_size;
+ gchar *cipher;
+ gchar *cipher_mode;
+ gchar *resilience;
+ gchar *hash;
+ guint64 max_hotzone_size;
+ guint32 sector_size;
+ gboolean new_volume_key;
+ gboolean offline = TRUE;
+// gchar *pbkdf_type;
+// BDCryptoLUKSPBKDF *pbkdf = NULL;
+ BDCryptoLUKSReencryptParams *params = NULL;
+
+ object = udisks_daemon_util_dup_object (block, &error);
+ if (object == NULL)
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ goto out;
+ }
+
+ daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
+ state = udisks_daemon_get_state (daemon);
+
+ udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
+ udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));
+
+ if (!udisks_daemon_util_get_caller_uid_sync (daemon, invocation, NULL /* GCancellable */, &caller_uid, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ goto out;
+ }
+
+ job = udisks_daemon_launch_simple_job (daemon,
+ UDISKS_OBJECT (object),
+ "block-encrypt",
+ caller_uid,
+ NULL);
+ if (job == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
+ "Failed to create a job object");
+ goto out;
+ }
+
+ udisks_linux_block_encrypted_lock (block);
+ // do stuff here
+ device = udisks_block_get_device (block);
+
+ context = bd_crypto_keyslot_context_new_passphrase ((const guint8 *) passphrase,
+ strlen(passphrase),
+ &error);
+ if (!context)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error encrypting block device %s (ctx): %s",
+ device,
+ error->message);
+ udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
+ udisks_linux_block_encrypted_unlock (block);
+ goto out;
+ }
+
+ g_variant_lookup (options, "key-size", "u", &key_size);
+ g_variant_lookup (options, "cipher", "&s", &cipher);
+ g_variant_lookup (options, "cipher-mode", "&s", &cipher_mode);
+ g_variant_lookup (options, "resilience", "&s", &resilience);
+ g_variant_lookup (options, "hash", "&s", &hash);
+ g_variant_lookup (options, "max-hotzone-size", "u", &max_hotzone_size);
+ g_variant_lookup (options, "sector-size", "u", §or_size);
+ g_variant_lookup (options, "new-volume_key", "b", &new_volume_key);
+ // `offline` is already determined
+
+ params = bd_crypto_luks_reencrypt_params_new (key_size, cipher, cipher_mode, resilience, hash, max_hotzone_size, sector_size, new_volume_key, offline, NULL);
+
+ if (! bd_crypto_luks_encrypt (device, params, context, NULL /* prog_func -- TODO */, &error))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error encrypting block device %s (enc): %s",
+ device,
+ error->message);
+ udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
+ udisks_linux_block_encrypted_unlock (block);
+ goto out;
+ }
+
+ //
+ udisks_linux_block_encrypted_unlock (block);
+
+ udisks_block_complete_encrypt (block, invocation);
+ udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), TRUE, NULL);
+
+ out:
+ if (object != NULL)
+ udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
+ if (state != NULL)
+ udisks_state_check (state);
+ g_clear_object (&object);
+ g_clear_error (&error);
+ return TRUE; /* returning TRUE means that we handled the method invocation */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
block_iface_init (UDisksBlockIface *iface)
{
@@ -4322,4 +4445,5 @@ block_iface_init (UDisksBlockIface *iface)
iface->handle_open_device = handle_open_device;
iface->handle_rescan = handle_rescan;
iface->handle_restore_encrypted_header = handle_restore_encrypted_header;
+ iface->handle_encrypt = handle_encrypt;
}
diff --git a/udisks/udisksclient.c b/udisks/udisksclient.c
index 56ca6ca57..38c1ccaf8 100644
--- a/udisks/udisksclient.c
+++ b/udisks/udisksclient.c
@@ -2738,6 +2738,7 @@ udisks_client_get_job_description_from_operation (const gchar *operation)
g_hash_table_insert (hash, (gpointer) "encrypted-header-backup", (gpointer) C_("job", "Backing Up Header of an Encrypted Device"));
g_hash_table_insert (hash, (gpointer) "encrypted-reencrypt", (gpointer) C_("job", "Reencrypting an Encrypted Device"));
g_hash_table_insert (hash, (gpointer) "block-restore-encrypted-header", (gpointer) C_("job", "Restoring Header of an Encrypted Device"));
+ g_hash_table_insert (hash, (gpointer) "block-encrypt", (gpointer) C_("job", "Encrypting a Block Device"));
g_hash_table_insert (hash, (gpointer) "swapspace-start", (gpointer) C_("job", "Starting Swap Device"));
g_hash_table_insert (hash, (gpointer) "swapspace-stop", (gpointer) C_("job", "Stopping Swap Device"));
g_hash_table_insert (hash, (gpointer) "swapspace-modify", (gpointer) C_("job", "Modifying Swap Device"));