Commit 30422ec7 authored by segfault3's avatar segfault3 Committed by Kai Lüke

Add TrueCrypt/VeraCrypt support

This is a combination of 4 commits:

- Disable "Encryption Options" for non-LUKS devices

- Disable "Change Passphrase" for non-LUKS devices

- Rename volume-content-luks to volume-content-crypto

- Add TCRYPT option widgets to the unlock dialog

This extends the unlock dialog by widgets which allow specifying the
parameters supported by TrueCrypt and VeraCrypt volumes. This includes:

 - Whether the volume to be unlocked is hidden.
 - Whether the volume to be unlocked is a system partition.
   Note: TrueCrypt and VeraCrypt only support encrypting Windows system
   partitions [1], so the label for this option is "Windows system".
 - Whether to use a PIM [2].
 - Whether to use one or multiple keyfiles. In the beginning there is
   only one button to choose a single keyfile. When a keyfile is chosen,
   another button appears below to allow selecting another keyfile, and
   so on.

Since TCRYPT volumes cannot be reliably detected as such, a label is
displayed at the top of the unlock dialog to indicate to the user that
this volume might not actually be encrypted.

[1] https://www.veracrypt.fr/en/System%20Encryption.html
[2] https://www.veracrypt.fr/en/Header%20Key%20Derivation.html
parent 64127fb4
......@@ -11,6 +11,8 @@
#include <glib/gi18n.h>
#include <libsecret/secret.h>
#include <stdlib.h>
#include <errno.h>
#include "gduapplication.h"
#include "gduwindow.h"
......@@ -35,16 +37,28 @@ typedef struct
UDisksObject *object;
UDisksBlock *block;
UDisksEncrypted *encrypted;
gchar* type;
GduWindow *window;
GtkBuilder *builder;
GtkWidget *dialog;
GtkWidget *unlock_button;
GtkWidget *infobar_vbox;
GtkWidget *entry;
GtkWidget *passphrase_entry;
GtkWidget *show_passphrase_check_button;
GtkWidget *tcrypt_hidden_check_button;
GtkWidget *tcrypt_system_check_button;
GtkWidget *pim_entry;
GList *tcrypt_keyfile_button_list;
gchar *passphrase;
GVariant *keyfiles;
guint num_keyfiles;
guint pim;
gboolean hidden_volume;
gboolean system_volume;
} DialogData;
static void
......@@ -62,10 +76,57 @@ dialog_data_free (DialogData *data)
if (data->builder != NULL)
g_object_unref (data->builder);
if (g_strcmp0 (data->type, "crypto_TCRYPT") == 0 || g_strcmp0 (data->type, "crypto_unknown") == 0)
// The elements are already freed by the builder / parent widget
g_list_free (data->tcrypt_keyfile_button_list);
g_free (data->type);
g_free (data->passphrase);
g_free (data);
}
static void
update_unlock_button_sensitivity (GObject *object,
gpointer user_data)
{
DialogData *data = user_data;
gboolean password_entered = gtk_entry_get_text_length (GTK_ENTRY (data->passphrase_entry)) > 0;
gboolean keyfile_chosen = (data->tcrypt_keyfile_button_list != NULL &&
g_list_length (data->tcrypt_keyfile_button_list) > 1);
gtk_widget_set_sensitive (data->unlock_button, password_entered || keyfile_chosen);
}
static void
on_tcrypt_keyfile_set (GObject *object,
gpointer user_data)
{
DialogData *data = user_data;
GtkWidget *button;
GtkWidget *sibling;
GtkGrid *grid;
GList *list;
grid = GTK_GRID (gtk_builder_get_object (data->builder, "unlock-device-grid"));
button = gtk_file_chooser_button_new (_("Select a Keyfile"), GTK_FILE_CHOOSER_ACTION_OPEN);
sibling = NULL;
for (list = data->tcrypt_keyfile_button_list; list != NULL; list = list->next)
sibling = (GTK_WIDGET (list->data));
gtk_grid_attach_next_to (grid, button, sibling, GTK_POS_BOTTOM, 1, 1);
gtk_widget_show (button);
data->tcrypt_keyfile_button_list = g_list_append (data->tcrypt_keyfile_button_list, button);
g_signal_connect (button, "file-set", G_CALLBACK (on_tcrypt_keyfile_set), data);
// Don't call this function again for this instance
g_signal_handlers_disconnect_by_func (object, on_tcrypt_keyfile_set, user_data);
update_unlock_button_sensitivity (object, user_data);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
......@@ -83,7 +144,7 @@ unlock_cb (UDisksEncrypted *encrypted,
&error))
{
gdu_utils_show_error (GTK_WINDOW (data->window),
_("Error unlocking encrypted device"),
_("Error unlocking device"),
error);
g_error_free (error);
}
......@@ -93,9 +154,20 @@ unlock_cb (UDisksEncrypted *encrypted,
static void
do_unlock (DialogData *data)
{
GVariantBuilder options_builder;
g_variant_builder_init (&options_builder, G_VARIANT_TYPE_VARDICT);
if (data->hidden_volume)
g_variant_builder_add (&options_builder, "{sv}", "hidden", g_variant_new_boolean (TRUE));
if (data->system_volume)
g_variant_builder_add (&options_builder, "{sv}", "system", g_variant_new_boolean (TRUE));
if (data->pim != 0)
g_variant_builder_add (&options_builder, "{sv}", "pim", g_variant_new_uint32 (data->pim));
if (data->num_keyfiles != 0)
g_variant_builder_add (&options_builder, "{sv}", "keyfiles", data->keyfiles);
udisks_encrypted_call_unlock (data->encrypted,
data->passphrase,
g_variant_new ("a{sv}", NULL), /* options */
g_variant_builder_end (&options_builder),
NULL, /* cancellable */
(GAsyncReadyCallback) unlock_cb,
data);
......@@ -105,15 +177,61 @@ static void
show_dialog (DialogData *data)
{
gint response;
gchar *err;
GError *error;
GVariantBuilder *keyfiles_builder;
GList *list;
const char* filename;
const char* text_pim;
guint64 tmp_pim;
gtk_widget_show_all (data->dialog);
gtk_widget_grab_focus (data->entry);
gtk_widget_grab_focus (data->passphrase_entry);
response = gtk_dialog_run (GTK_DIALOG (data->dialog));
if (response == GTK_RESPONSE_OK)
{
gtk_widget_hide (data->dialog);
data->passphrase = g_strdup (gtk_entry_get_text (GTK_ENTRY (data->entry)));
data->passphrase = g_strdup (gtk_entry_get_text (GTK_ENTRY (data->passphrase_entry)));
if (g_strcmp0 (data->type, "crypto_TCRYPT") == 0 || g_strcmp0 (data->type, "crypto_unknown") == 0)
{
data->hidden_volume = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->tcrypt_hidden_check_button));
data->system_volume = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->tcrypt_system_check_button));
// Add keyfiles
data->num_keyfiles = 0;
keyfiles_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
for (list = data->tcrypt_keyfile_button_list; list != NULL; list = list->next)
{
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (list->data));
if (filename == NULL)
continue;
g_variant_builder_add (keyfiles_builder, "s", filename);
data->num_keyfiles += 1;
}
data->keyfiles = g_variant_new ("as", keyfiles_builder);
g_variant_builder_unref (keyfiles_builder);
text_pim = gtk_entry_get_text (GTK_ENTRY (data->pim_entry));
if (text_pim && strlen (text_pim) > 0)
{
errno = 0;
tmp_pim = strtoul ( text_pim, &err, 10);
if (*err || errno || tmp_pim <= 0 || tmp_pim > G_MAXUINT32)
{
error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
_("Invalid PIM"));
gdu_utils_show_error (GTK_WINDOW(data->window),
_("Error unlocking device"),
error);
g_error_free (error);
dialog_data_free (data);
return;
}
data->pim = tmp_pim;
}
}
do_unlock (data);
}
else
......@@ -143,7 +261,7 @@ luks_find_passphrase_cb (GObject *source,
_("The encryption passphrase was retrieved from the keyring"),
NULL);
gtk_box_pack_start (GTK_BOX (data->infobar_vbox), infobar, TRUE, TRUE, 0);
gtk_entry_set_text (GTK_ENTRY (data->entry), passphrase);
gtk_entry_set_text (GTK_ENTRY (data->passphrase_entry), passphrase);
}
else
{
......@@ -166,24 +284,65 @@ gdu_unlock_dialog_show (GduWindow *window,
data->block = udisks_object_peek_block (object);
data->encrypted = udisks_object_peek_encrypted (object);
data->window = g_object_ref (window);
data->type = udisks_block_dup_id_type (data->block);
data->dialog = GTK_WIDGET (gdu_application_new_widget (gdu_window_get_application (window),
"unlock-device-dialog.ui",
"unlock-device-dialog",
&data->builder));
data->unlock_button = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-unlock-button"));
data->infobar_vbox = GTK_WIDGET (gtk_builder_get_object (data->builder, "infobar-vbox"));
data->entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-passphrase-entry"));
data->passphrase_entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-passphrase-entry"));
data->show_passphrase_check_button = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-show-passphrase-check-button"));
// Add TCRYPT options if the device is (possibly) a TCRYPT volume
if (g_strcmp0 (data->type, "crypto_TCRYPT") == 0 || g_strcmp0 (data->type, "crypto_unknown") == 0)
{
GtkWidget *volume_type_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-volume-type-label"));
GtkWidget *keyfiles_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-keyfiles-label"));
GtkWidget *pim_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-pim-label"));
GtkWidget *button = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-tcrypt-keyfile-chooser-button"));
gtk_window_set_title (GTK_WINDOW (data->dialog), _("Set options to unlock"));
data->tcrypt_hidden_check_button = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-tcrypt-hidden-check-button"));
data->tcrypt_system_check_button = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-tcrypt-system-check-button"));
data->pim_entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "unlock-device-pim-entry"));
data->tcrypt_keyfile_button_list = NULL;
data->tcrypt_keyfile_button_list = g_list_append (data->tcrypt_keyfile_button_list, button);
gtk_widget_set_visible (volume_type_label, TRUE);
gtk_widget_set_visible (pim_label, TRUE);
gtk_widget_set_visible (keyfiles_label, TRUE);
gtk_widget_set_visible (button, TRUE);
gtk_widget_set_visible (data->tcrypt_hidden_check_button, TRUE);
gtk_widget_set_visible (data->tcrypt_system_check_button, TRUE);
gtk_widget_set_visible (data->pim_entry, TRUE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->tcrypt_hidden_check_button), FALSE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->tcrypt_system_check_button), FALSE);
gtk_entry_set_text (GTK_ENTRY (data->pim_entry), "");
g_signal_connect (button, "file-set", G_CALLBACK (on_tcrypt_keyfile_set), data);
if (g_strcmp0 (data->type, "crypto_unknown") == 0)
{
GtkWidget *unknown_crypto_label;
unknown_crypto_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "unknown-crypto-label"));
gtk_widget_set_visible (unknown_crypto_label, TRUE);
gtk_widget_set_no_show_all (unknown_crypto_label, FALSE);
}
}
gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (data->window));
gtk_dialog_set_default_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->show_passphrase_check_button), FALSE);
gtk_entry_set_text (GTK_ENTRY (data->entry), "");
gtk_entry_set_text (GTK_ENTRY (data->passphrase_entry), "");
g_signal_connect (data->passphrase_entry, "changed", G_CALLBACK (update_unlock_button_sensitivity), data);
g_object_bind_property (data->show_passphrase_check_button,
"active",
data->entry,
data->passphrase_entry,
"visibility",
G_BINDING_SYNC_CREATE);
......
......@@ -2788,14 +2788,18 @@ update_device_page_for_block (GduWindow *window,
{
show_flags->volume_buttons |= SHOW_FLAGS_VOLUME_BUTTONS_ENCRYPTED_LOCK;
/* Translators: Shown as in-use part of 'Contents' if the encrypted device is unlocked */
in_use_markup = g_strdup (C_("volume-content-luks", "Unlocked"));
in_use_markup = g_strdup (C_("volume-content-crypto", "Unlocked"));
}
else
{
show_flags->volume_buttons |= SHOW_FLAGS_VOLUME_BUTTONS_ENCRYPTED_UNLOCK;
/* Translators: Shown as in-use part of 'Contents' if the encrypted device is unlocked */
in_use_markup = g_strdup (C_("volume-content-luks", "Locked"));
in_use_markup = g_strdup (C_("volume-content-crypto", "Locked"));
}
}
if (g_strcmp0 (udisks_block_get_id_type (block), "crypto_LUKS") == 0)
{
show_flags->volume_menu |= SHOW_FLAGS_VOLUME_MENU_CONFIGURE_CRYPTTAB;
show_flags->volume_menu |= SHOW_FLAGS_VOLUME_MENU_CHANGE_PASSPHRASE;
}
......
......@@ -2,6 +2,7 @@
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="unlock-device-dialog">
<property name="width_request">400</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="title" translatable="yes">Enter passphrase to unlock</property>
......@@ -14,6 +15,8 @@
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<property name="margin_left">20</property>
<property name="margin_right">20</property>
<child>
<object class="GtkBox" id="infobar-vbox">
<property name="visible">True</property>
......@@ -30,7 +33,24 @@
</packing>
</child>
<child>
<object class="GtkGrid" id="grid1">
<object class="GtkLabel" id="unknown-crypto-label">
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">This volume might be a VeraCrypt volume as it contains random data.</property>
<property name="wrap">True</property>
<property name="width_chars">30</property>
<property name="max_width_chars">30</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="unlock-device-grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">6</property>
......@@ -56,6 +76,7 @@
</child>
<child>
<object class="GtkEntry" id="unlock-device-passphrase-entry">
<property name="placeholder-text" translatable="yes">If specified</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
......@@ -88,6 +109,122 @@
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="unlock-device-volume-type-label">
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Volume type</property>
<property name="use_underline">True</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="unlock-device-volume-type-box">
<property name="spacing">10</property>
<property name="margin_top">3</property>
<property name="margin_bottom">3</property>
<child>
<object class="GtkCheckButton" id="unlock-device-tcrypt-hidden-check-button">
<property name="label" translatable="yes">_Hidden</property>
<property name="tooltip_markup" translatable="yes">Instead of unlocking this volume, attempt to unlock a secondary volume hidden inside.</property>
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
</child>
<child>
<object class="GtkCheckButton" id="unlock-device-tcrypt-system-check-button">
<property name="label" translatable="yes">Windows _system</property>
<property name="tooltip_markup" translatable="yes">Unlock an encrypted Windows system partition or drive.</property>
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="unlock-device-pim-label">
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">PI_M</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">unlock-device-pim-entry</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="unlock-device-pim-entry">
<property name="placeholder-text" translatable="yes">If specified</property>
<property name="tooltip_markup" translatable="yes">If set, the VeraCrypt PIM (Personal Iterations Multiplier) numeric value to use for this volume.</property>
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="activates_default">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="unlock-device-keyfiles-label">
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Keyfiles</property>
<property name="use_underline">True</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="unlock-device-tcrypt-keyfile-chooser-button">
<property name="title" translatable="yes">Select a Keyfile</property>
<property name="visible">False</property>
<property name="no_show_all">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<placeholder/>
</child>
......@@ -117,9 +254,10 @@
</packing>
</child>
<child>
<object class="GtkButton" id="button6">
<object class="GtkButton" id="unlock-device-unlock-button">
<property name="label" translatable="yes">_Unlock</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">True</property>
......@@ -143,7 +281,7 @@
</child>
<action-widgets>
<action-widget response="-6">button5</action-widget>
<action-widget response="-5">button6</action-widget>
<action-widget response="-5">unlock-device-unlock-button</action-widget>
</action-widgets>
</object>
</interface>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment