Imported Upstream version 1.6.7
[platform/upstream/cryptsetup.git] / src / cryptsetup.c
index 0cc7a49..8fc4d6c 100644 (file)
@@ -1,13 +1,15 @@
 /*
  * cryptsetup - setup cryptographic volumes for dm-crypt
  *
 /*
  * cryptsetup - setup cryptographic volumes for dm-crypt
  *
- * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
+ * Copyright (C) 2004, Jana Saout <jana@saout.de>
  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
- * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2015, Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2015, Milan Broz
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,6 +35,7 @@ static const char *opt_master_key_file = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
 static const char *opt_header_device = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
 static const char *opt_header_device = NULL;
+static const char *opt_type = "luks";
 static int opt_key_size = 0;
 static long opt_keyfile_size = 0;
 static long opt_new_keyfile_size = 0;
 static int opt_key_size = 0;
 static long opt_keyfile_size = 0;
 static long opt_new_keyfile_size = 0;
@@ -54,69 +57,25 @@ static int opt_urandom = 0;
 static int opt_dump_master_key = 0;
 static int opt_shared = 0;
 static int opt_allow_discards = 0;
 static int opt_dump_master_key = 0;
 static int opt_shared = 0;
 static int opt_allow_discards = 0;
+static int opt_perf_same_cpu_crypt = 0;
+static int opt_perf_submit_from_crypt_cpus = 0;
 static int opt_test_passphrase = 0;
 static int opt_test_passphrase = 0;
-static int opt_hidden = 0;
+static int opt_tcrypt_hidden = 0;
+static int opt_tcrypt_system = 0;
+static int opt_tcrypt_backup = 0;
+static int opt_veracrypt = 0;
 
 static const char **action_argv;
 static int action_argc;
 static const char *null_action_argv[] = {NULL, NULL};
 
 
 static const char **action_argv;
 static int action_argc;
 static const char *null_action_argv[] = {NULL, NULL};
 
-static int action_create(int arg);
-static int action_remove(int arg);
-static int action_resize(int arg);
-static int action_status(int arg);
-static int action_benchmark(int arg);
-static int action_luksFormat(int arg);
-static int action_luksOpen(int arg);
-static int action_luksAddKey(int arg);
-static int action_luksKillSlot(int arg);
-static int action_luksRemoveKey(int arg);
-static int action_luksChangeKey(int arg);
-static int action_isLuks(int arg);
-static int action_luksUUID(int arg);
-static int action_luksDump(int arg);
-static int action_luksSuspend(int arg);
-static int action_luksResume(int arg);
-static int action_luksBackup(int arg);
-static int action_luksRestore(int arg);
-static int action_loopaesOpen(int arg);
-static int action_luksRepair(int arg);
-static int action_tcryptOpen(int arg);
+static const char *uuid_or_device_header(const char **data_device)
+{
+       if (data_device)
+               *data_device = opt_header_device ? action_argv[0] : NULL;
 
 
-static struct action_type {
-       const char *type;
-       int (*handler)(int);
-       int arg;
-       int required_action_argc;
-       int required_memlock;
-       const char *arg_desc;
-       const char *desc;
-} action_types[] = {
-       { "create",     action_create,          0, 2, 1, N_("<name> <device>"),N_("create device") },
-       { "remove",     action_remove,          0, 1, 1, N_("<name>"), N_("remove device") },
-       { "resize",     action_resize,          0, 1, 1, N_("<name>"), N_("resize active device") },
-       { "status",     action_status,          0, 1, 0, N_("<name>"), N_("show device status") },
-       { "benchmark",  action_benchmark,       0, 0, 0, N_("<name>"), N_("benchmark cipher") },
-       { "repair",     action_luksRepair,      0, 1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
-       { "luksFormat", action_luksFormat,      0, 1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
-       { "luksOpen",   action_luksOpen,        0, 2, 1, N_("<device> <name> "), N_("open LUKS device as mapping <name>") },
-       { "luksAddKey", action_luksAddKey,      0, 1, 1, N_("<device> [<new key file>]"), N_("add key to LUKS device") },
-       { "luksRemoveKey",action_luksRemoveKey, 0, 1, 1, N_("<device> [<key file>]"), N_("removes supplied key or key file from LUKS device") },
-       { "luksChangeKey",action_luksChangeKey, 0, 1, 1, N_("<device> [<key file>]"), N_("changes supplied key or key file of LUKS device") },
-       { "luksKillSlot",  action_luksKillSlot, 0, 2, 1, N_("<device> <key slot>"), N_("wipes key with number <key slot> from LUKS device") },
-       { "luksUUID",   action_luksUUID,        0, 1, 0, N_("<device>"), N_("print UUID of LUKS device") },
-       { "isLuks",     action_isLuks,          0, 1, 0, N_("<device>"), N_("tests <device> for LUKS partition header") },
-       { "luksClose",  action_remove,          0, 1, 1, N_("<name>"), N_("remove LUKS mapping") },
-       { "luksDump",   action_luksDump,        0, 1, 1, N_("<device>"), N_("dump LUKS partition information") },
-       { "luksSuspend",action_luksSuspend,     0, 1, 1, N_("<device>"), N_("Suspend LUKS device and wipe key (all IOs are frozen).") },
-       { "luksResume", action_luksResume,      0, 1, 1, N_("<device>"), N_("Resume suspended LUKS device.") },
-       { "luksHeaderBackup",action_luksBackup, 0, 1, 1, N_("<device>"), N_("Backup LUKS device header and keyslots") },
-       { "luksHeaderRestore",action_luksRestore,0,1, 1, N_("<device>"), N_("Restore LUKS device header and keyslots") },
-       { "loopaesOpen",action_loopaesOpen,     0, 2, 1, N_("<device> <name> "), N_("open loop-AES device as mapping <name>") },
-       { "loopaesClose",action_remove,         0, 1, 1, N_("<name>"), N_("remove loop-AES mapping") },
-       { "tcryptOpen", action_tcryptOpen,      0, 2, 1, N_("<device> <name> "), N_("open TCRYPT device as mapping <name>") },
-       { NULL, NULL, 0, 0, 0, NULL, NULL }
-};
+       return uuid_or_device(opt_header_device ?: action_argv[0]);
+}
 
 static int _verify_passphrase(int def)
 {
 
 static int _verify_passphrase(int def)
 {
@@ -136,7 +95,22 @@ static int _verify_passphrase(int def)
        return def;
 }
 
        return def;
 }
 
-static int action_create(int arg __attribute__((unused)))
+static void _set_activation_flags(uint32_t *flags)
+{
+       if (opt_readonly)
+               *flags |= CRYPT_ACTIVATE_READONLY;
+
+       if (opt_allow_discards)
+               *flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+
+       if (opt_perf_same_cpu_crypt)
+               *flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT;
+
+       if (opt_perf_submit_from_crypt_cpus)
+               *flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
+}
+
+static int action_open_plain(void)
 {
        struct crypt_device *cd = NULL;
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
 {
        struct crypt_device *cd = NULL;
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
@@ -150,27 +124,35 @@ static int action_create(int arg __attribute__((unused)))
        size_t passwordLen;
        size_t key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS) / 8;
        uint32_t activate_flags = 0;
        size_t passwordLen;
        size_t key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS) / 8;
        uint32_t activate_flags = 0;
+       int keyfile_limited = 0;
        int r;
 
        int r;
 
-       if (params.hash && !strcmp(params.hash, "plain"))
-               params.hash = NULL;
-
-       /* FIXME: temporary hack */
-       if (opt_key_file && strcmp(opt_key_file, "-"))
-               params.hash = NULL;
-
-       if ((opt_keyfile_offset || opt_keyfile_size) && opt_key_file)
-               log_std(("Ignoring keyfile offset and size options, keyfile read "
-                        "size is always the same as encryption key size.\n"));
-
        r = crypt_parse_name_and_mode(opt_cipher ?: DEFAULT_CIPHER(PLAIN),
                                      cipher, NULL, cipher_mode);
        if (r < 0) {
        r = crypt_parse_name_and_mode(opt_cipher ?: DEFAULT_CIPHER(PLAIN),
                                      cipher, NULL, cipher_mode);
        if (r < 0) {
-               log_err("No known cipher specification pattern detected.\n");
+               log_err(_("No known cipher specification pattern detected.\n"));
                goto out;
        }
 
                goto out;
        }
 
-       if ((r = crypt_init(&cd, action_argv[1])))
+       if (opt_key_file && strcmp(opt_key_file, "-") != 0)
+               keyfile_limited = 1;
+
+       /* FIXME: temporary hack, no hashing for keyfiles in plain mode */
+       if (opt_key_file && keyfile_limited) {
+               params.hash = NULL;
+               if (!opt_batch_mode && opt_hash)
+                       log_std(_("WARNING: The --hash parameter is being ignored "
+                                "in plain mode with keyfile specified.\n"));
+       }
+
+       if (params.hash && !strcmp(params.hash, "plain"))
+               params.hash = NULL;
+
+       if (!opt_batch_mode && !params.hash && opt_key_file && keyfile_limited && opt_keyfile_size)
+               log_std(_("WARNING: The --keyfile-size option is being ignored, "
+                        "the read size is the same as the encryption key size.\n"));
+
+       if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
@@ -181,35 +163,36 @@ static int action_create(int arg __attribute__((unused)))
                         NULL, NULL,
                         key_size,
                         &params);
                         NULL, NULL,
                         key_size,
                         &params);
+       check_signal(&r);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       if (opt_readonly)
-               activate_flags |= CRYPT_ACTIVATE_READONLY;
-
        if (opt_shared)
                activate_flags |= CRYPT_ACTIVATE_SHARED;
 
        if (opt_shared)
                activate_flags |= CRYPT_ACTIVATE_SHARED;
 
-       if (opt_allow_discards)
-               activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+       _set_activation_flags(&activate_flags);
 
 
-       if (opt_key_file)
-               /* With hashing, read the whole keyfile */
-               r = crypt_activate_by_keyfile_offset(cd, action_argv[0],
+       if (opt_key_file) {
+               /* If no hash, key is read directly, read size is always key_size
+                * (possible opt_keyfile_size is ignored.
+                * If hash is specified, opt_keyfile_size is applied.
+                * The opt_keyfile_offset is applied always.
+                */
+               r = crypt_activate_by_keyfile_offset(cd, action_argv[1],
                        CRYPT_ANY_SLOT, opt_key_file,
                        CRYPT_ANY_SLOT, opt_key_file,
-                       params.hash ? 0 : key_size, 0,
+                       params.hash ? opt_keyfile_size : key_size, opt_keyfile_offset,
                        activate_flags);
                        activate_flags);
-       else {
-               r = crypt_get_key(_("Enter passphrase: "),
+       else {
+               r = tools_get_key(_("Enter passphrase: "),
                                  &password, &passwordLen,
                                  opt_keyfile_offset, opt_keyfile_size,
                                  NULL, opt_timeout,
                                  &password, &passwordLen,
                                  opt_keyfile_offset, opt_keyfile_size,
                                  NULL, opt_timeout,
-                                 _verify_passphrase(0),
+                                 _verify_passphrase(0), 0,
                                  cd);
                if (r < 0)
                        goto out;
 
                                  cd);
                if (r < 0)
                        goto out;
 
-               r = crypt_activate_by_passphrase(cd, action_argv[0],
+               r = crypt_activate_by_passphrase(cd, action_argv[1],
                        CRYPT_ANY_SLOT, password, passwordLen, activate_flags);
        }
 out:
                        CRYPT_ANY_SLOT, password, passwordLen, activate_flags);
        }
 out:
@@ -219,7 +202,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_loopaesOpen(int arg __attribute__((unused)))
+static int action_open_loopaes(void)
 {
        struct crypt_device *cd = NULL;
        struct crypt_params_loopaes params = {
 {
        struct crypt_device *cd = NULL;
        struct crypt_params_loopaes params = {
@@ -236,39 +219,81 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
                return -EINVAL;
        }
 
                return -EINVAL;
        }
 
-       if (opt_readonly)
-               activate_flags |= CRYPT_ACTIVATE_READONLY;
-
-       if (opt_allow_discards)
-               activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+       _set_activation_flags(&activate_flags);
 
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        r = crypt_format(cd, CRYPT_LOOPAES, opt_cipher ?: DEFAULT_LOOPAES_CIPHER,
                         NULL, NULL, NULL, key_size, &params);
 
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        r = crypt_format(cd, CRYPT_LOOPAES, opt_cipher ?: DEFAULT_LOOPAES_CIPHER,
                         NULL, NULL, NULL, key_size, &params);
+       check_signal(&r);
        if (r < 0)
                goto out;
 
        r = crypt_activate_by_keyfile_offset(cd, action_argv[1], CRYPT_ANY_SLOT,
                                      opt_key_file, opt_keyfile_size,
        if (r < 0)
                goto out;
 
        r = crypt_activate_by_keyfile_offset(cd, action_argv[1], CRYPT_ANY_SLOT,
                                      opt_key_file, opt_keyfile_size,
-                                     opt_keyfile_size, activate_flags);
+                                     opt_keyfile_offset, activate_flags);
 out:
        crypt_free(cd);
 
        return r;
 }
 
 out:
        crypt_free(cd);
 
        return r;
 }
 
-static int action_tcryptOpen(int arg __attribute__((unused)))
+static int tcrypt_load(struct crypt_device *cd, struct crypt_params_tcrypt *params)
+{
+       int r, tries = opt_tries, eperm = 0;
+
+       do {
+               /* TCRYPT header is encrypted, get passphrase now */
+               r = tools_get_key(_("Enter passphrase: "),
+                                 CONST_CAST(char**)&params->passphrase,
+                                 &params->passphrase_size, 0, 0, NULL, opt_timeout,
+                                _verify_passphrase(0), 0, cd);
+               if (r < 0)
+                       continue;
+
+               if (opt_tcrypt_hidden)
+                       params->flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+               if (opt_tcrypt_system)
+                       params->flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
+
+               if (opt_tcrypt_backup)
+                       params->flags |= CRYPT_TCRYPT_BACKUP_HEADER;
+
+               r = crypt_load(cd, CRYPT_TCRYPT, params);
+
+               if (r == -EPERM) {
+                       log_err(_("No device header detected with this passphrase.\n"));
+                       eperm = 1;
+               }
+
+               if (r < 0) {
+                       crypt_safe_free(CONST_CAST(char*)params->passphrase);
+                       params->passphrase = NULL;
+                       params->passphrase_size = 0;
+               }
+               check_signal(&r);
+       } while (r == -EPERM && (--tries > 0));
+
+       /* Report wrong passphrase if at least one try failed */
+       if (eperm && r == -EPIPE)
+               r = -EPERM;
+
+       return r;
+}
+
+static int action_open_tcrypt(void)
 {
        struct crypt_device *cd = NULL;
        struct crypt_params_tcrypt params = {
                .keyfiles = opt_keyfiles,
                .keyfiles_count = opt_keyfiles_count,
 {
        struct crypt_device *cd = NULL;
        struct crypt_params_tcrypt params = {
                .keyfiles = opt_keyfiles,
                .keyfiles_count = opt_keyfiles_count,
-               .flags = CRYPT_TCRYPT_LEGACY_MODES,
+               .flags = CRYPT_TCRYPT_LEGACY_MODES |
+                        (opt_veracrypt ? CRYPT_TCRYPT_VERA_MODES : 0),
        };
        const char *activated_name;
        };
        const char *activated_name;
-       uint32_t flags = 0;
+       uint32_t activate_flags = 0;
        int r;
 
        activated_name = opt_test_passphrase ? NULL : action_argv[1];
        int r;
 
        activated_name = opt_test_passphrase ? NULL : action_argv[1];
@@ -276,33 +301,91 @@ static int action_tcryptOpen(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       /* TCRYPT header is encrypted, get passphrase now */
-       r = crypt_get_key(_("Enter passphrase: "),
-                         CONST_CAST(char**)&params.passphrase,
-                         &params.passphrase_size, 0, 0, NULL, opt_timeout,
-                         _verify_passphrase(0), cd);
+       r = tcrypt_load(cd, &params);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       if (opt_hidden)
-               params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+       _set_activation_flags(&activate_flags);
 
 
-       r = crypt_load(cd, CRYPT_TCRYPT, &params);
+       if (activated_name)
+               r = crypt_activate_by_volume_key(cd, activated_name, NULL, 0, activate_flags);
+out:
+       crypt_free(cd);
+       crypt_safe_free(CONST_CAST(char*)params.passphrase);
+       return r;
+}
+
+static int tcryptDump_with_volume_key(struct crypt_device *cd)
+{
+       char *vk = NULL;
+       size_t vk_size;
+       unsigned i;
+       int r;
+
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
+       if (!yesDialog(
+           _("Header dump with volume key is sensitive information\n"
+             "which allows access to encrypted partition without passphrase.\n"
+             "This dump should be always stored encrypted on safe place."),
+             NULL))
+               return -EPERM;
+
+       vk_size = crypt_get_volume_key_size(cd);
+       vk = crypt_safe_alloc(vk_size);
+       if (!vk)
+               return -ENOMEM;
+
+       r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, vk, &vk_size, NULL, 0);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       if (opt_readonly)
-               flags |= CRYPT_ACTIVATE_READONLY;
+       log_std("TCRYPT header information for %s\n", crypt_get_device_name(cd));
+       log_std("Cipher chain:  \t%s\n", crypt_get_cipher(cd));
+       log_std("Cipher mode:   \t%s\n", crypt_get_cipher_mode(cd));
+       log_std("Payload offset:\t%d\n", (int)crypt_get_data_offset(cd));
+       log_std("MK bits:       \t%d\n", (int)vk_size * 8);
+       log_std("MK dump:\t");
 
 
-       if (activated_name)
-               r = crypt_activate_by_volume_key(cd, activated_name, NULL, 0, flags);
+       for(i = 0; i < vk_size; i++) {
+               if (i && !(i % 16))
+                       log_std("\n\t\t");
+               log_std("%02hhx ", (char)vk[i]);
+       }
+       log_std("\n");
+out:
+       crypt_safe_free(vk);
+       return r;
+}
+
+static int action_tcryptDump(void)
+{
+       struct crypt_device *cd = NULL;
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+               .flags = CRYPT_TCRYPT_LEGACY_MODES |
+                        (opt_veracrypt ? CRYPT_TCRYPT_VERA_MODES : 0),
+       };
+       int r;
+
+       if ((r = crypt_init(&cd, action_argv[0])))
+               goto out;
+
+       r = tcrypt_load(cd, &params);
+       if (r < 0)
+               goto out;
+
+       if (opt_dump_master_key)
+               r = tcryptDump_with_volume_key(cd);
+       else
+               r = crypt_dump(cd);
 out:
        crypt_free(cd);
        crypt_safe_free(CONST_CAST(char*)params.passphrase);
        return r;
 }
 
 out:
        crypt_free(cd);
        crypt_safe_free(CONST_CAST(char*)params.passphrase);
        return r;
 }
 
-static int action_remove(int arg __attribute__((unused)))
+static int action_close(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -315,7 +398,7 @@ static int action_remove(int arg __attribute__((unused)))
        return r;
 }
 
        return r;
 }
 
-static int action_resize(int arg __attribute__((unused)))
+static int action_resize(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -328,18 +411,17 @@ static int action_resize(int arg __attribute__((unused)))
        return r;
 }
 
        return r;
 }
 
-static int action_status(int arg __attribute__((unused)))
+static int action_status(void)
 {
        crypt_status_info ci;
        struct crypt_active_device cad;
        struct crypt_device *cd = NULL;
 {
        crypt_status_info ci;
        struct crypt_active_device cad;
        struct crypt_device *cd = NULL;
-       struct stat st;
        char *backing_file;
        const char *device;
        int path = 0, r = 0;
 
        /* perhaps a path, not a dm device name */
        char *backing_file;
        const char *device;
        int path = 0, r = 0;
 
        /* perhaps a path, not a dm device name */
-       if (strchr(action_argv[0], '/') && !stat(action_argv[0], &st))
+       if (strchr(action_argv[0], '/'))
                path = 1;
 
        ci = crypt_status(NULL, action_argv[0]);
                path = 1;
 
        ci = crypt_status(NULL, action_argv[0]);
@@ -364,10 +446,10 @@ static int action_status(int arg __attribute__((unused)))
                                ci == CRYPT_BUSY ? " and is in use" : "");
 
                r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
                                ci == CRYPT_BUSY ? " and is in use" : "");
 
                r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
-               if (r < 0 || !crypt_get_type(cd))
+               if (r < 0)
                        goto out;
 
                        goto out;
 
-               log_std("  type:    %s\n", crypt_get_type(cd));
+               log_std("  type:    %s\n", crypt_get_type(cd) ?: "n/a");
 
                r = crypt_get_active_device(cd, action_argv[0], &cad);
                if (r < 0)
 
                r = crypt_get_active_device(cd, action_argv[0], &cad);
                if (r < 0)
@@ -388,8 +470,13 @@ static int action_status(int arg __attribute__((unused)))
                        log_std("  skipped: %" PRIu64 " sectors\n", cad.iv_offset);
                log_std("  mode:    %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
                                           "readonly" : "read/write");
                        log_std("  skipped: %" PRIu64 " sectors\n", cad.iv_offset);
                log_std("  mode:    %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
                                           "readonly" : "read/write");
-               if (cad.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS)
-                       log_std("  flags:   discards\n");
+               if (cad.flags & (CRYPT_ACTIVATE_ALLOW_DISCARDS|
+                                CRYPT_ACTIVATE_ALLOW_DISCARDS|
+                                CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS))
+                       log_std("  flags:   %s%s%s\n",
+                               (cad.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) ? "discards " : "",
+                               (cad.flags & CRYPT_ACTIVATE_SAME_CPU_CRYPT) ? "same_cpu_crypt " : "",
+                               (cad.flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) ? "submit_from_crypt_cpus" : "");
        }
 out:
        crypt_free(cd);
        }
 out:
        crypt_free(cd);
@@ -398,11 +485,49 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_benchmark(int arg __attribute__((unused)))
+static int action_benchmark_kdf(const char *hash)
+{
+       uint64_t kdf_iters;
+       int r;
+
+       r = crypt_benchmark_kdf(NULL, "pbkdf2", hash, "foo", 3, "bar", 3,
+                               &kdf_iters);
+       if (r < 0)
+               log_std("PBKDF2-%-9s     N/A\n", hash);
+       else
+               log_std("PBKDF2-%-9s %7" PRIu64 " iterations per second\n",
+                       hash, kdf_iters);
+       return r;
+}
+
+static int benchmark_cipher_loop(const char *cipher, const char *cipher_mode,
+                                size_t volume_key_size, size_t iv_size,
+                                double *encryption_mbs, double *decryption_mbs)
+{
+       int r, buffer_size = 1024 * 1024;
+
+       do {
+               r = crypt_benchmark(NULL, cipher, cipher_mode,
+                                   volume_key_size, iv_size, buffer_size,
+                                   encryption_mbs, decryption_mbs);
+               if (r == -ERANGE) {
+                       if (buffer_size < 1024 * 1024 * 65)
+                               buffer_size *= 2;
+                       else {
+                               log_err(_("Result of benchmark is not reliable.\n"));
+                               r = -ENOENT;
+                       }
+               }
+       } while (r == -ERANGE);
+
+       return r;
+}
+
+static int action_benchmark(void)
 {
        static struct {
 {
        static struct {
-               char *cipher;
-               char *mode;
+               const char *cipher;
+               const char *mode;
                size_t key_size;
                size_t iv_size;
        } bciphers[] = {
                size_t key_size;
                size_t iv_size;
        } bciphers[] = {
@@ -420,17 +545,20 @@ static int action_benchmark(int arg __attribute__((unused)))
                { "twofish", "xts", 64, 16 },
                {  NULL, NULL, 0, 0 }
        };
                { "twofish", "xts", 64, 16 },
                {  NULL, NULL, 0, 0 }
        };
-       char *header = "# Tests are approximate using memory only (no storage IO).\n"
-                       "# Algorithm | Key | Encryption | Decryption\n";
+       static const char *bkdfs[] = {
+               "sha1", "sha256", "sha512", "ripemd160", "whirlpool", NULL
+       };
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
        double enc_mbr = 0, dec_mbr = 0;
        int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
        double enc_mbr = 0, dec_mbr = 0;
        int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
-       int iv_size = 16;
-       int buffer_size = 1024 * 1024;
+       int iv_size = 16, skipped = 0;
        char *c;
        int i, r;
 
        char *c;
        int i, r;
 
-       if (opt_cipher) {
+       log_std(_("# Tests are approximate using memory only (no storage IO).\n"));
+       if (opt_hash) {
+               r = action_benchmark_kdf(opt_hash);
+       } else if (opt_cipher) {
                r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
                if (r < 0) {
                        log_err(_("No known cipher specification pattern detected.\n"));
                r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
                if (r < 0) {
                        log_err(_("No known cipher specification pattern detected.\n"));
@@ -440,37 +568,61 @@ static int action_benchmark(int arg __attribute__((unused)))
                        *c = '\0';
 
                /* FIXME: not really clever :) */
                        *c = '\0';
 
                /* FIXME: not really clever :) */
-               if (strstr(cipher, "des"))
+               if (strstr(cipher, "des") ||
+                   strstr(cipher, "blowfish") ||
+                   strstr(cipher, "cast5"))
                        iv_size = 8;
 
                        iv_size = 8;
 
-               r = crypt_benchmark(NULL, cipher, cipher_mode,
-                                   key_size / 8, iv_size, buffer_size,
-                                   &enc_mbr, &dec_mbr);
+               if (!strcmp(cipher_mode, "ecb"))
+                       iv_size = 0;
+
+               r = benchmark_cipher_loop(cipher, cipher_mode,
+                                         key_size / 8, iv_size,
+                                         &enc_mbr, &dec_mbr);
                if (!r) {
                if (!r) {
-                       log_std("%s", header);
-                       strncat(cipher, "-", MAX_CIPHER_LEN);
-                       strncat(cipher, cipher_mode, MAX_CIPHER_LEN);
-                       log_std("%11s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
-                               cipher, key_size, enc_mbr, dec_mbr);
-               } else
-                       log_err(_("Cannot benchmark %s.\n"), cipher);
+                       log_std(N_("#  Algorithm | Key |  Encryption |  Decryption\n"));
+                       log_std("%8s-%s  %4db  %6.1f MiB/s  %6.1f MiB/s\n",
+                               cipher, cipher_mode, key_size, enc_mbr, dec_mbr);
+               } else if (r == -ENOENT)
+                       log_err(_("Cipher %s is not available.\n"), opt_cipher);
        } else {
        } else {
-               log_std("%s", header);
+               for (i = 0; bkdfs[i]; i++) {
+                       r = action_benchmark_kdf(bkdfs[i]);
+                       check_signal(&r);
+                       if (r == -EINTR)
+                               break;
+               }
                for (i = 0; bciphers[i].cipher; i++) {
                for (i = 0; bciphers[i].cipher; i++) {
-                       r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
+                       r = benchmark_cipher_loop(bciphers[i].cipher, bciphers[i].mode,
                                            bciphers[i].key_size, bciphers[i].iv_size,
                                            bciphers[i].key_size, bciphers[i].iv_size,
-                                           buffer_size, &enc_mbr, &dec_mbr);
+                                           &enc_mbr, &dec_mbr);
+                       check_signal(&r);
+                       if (r == -ENOTSUP || r == -EINTR)
+                               break;
+                       if (r == -ENOENT)
+                               skipped++;
+                       if (i == 0)
+                               log_std(N_("#  Algorithm | Key |  Encryption |  Decryption\n"));
+
                        snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
                                 bciphers[i].cipher, bciphers[i].mode);
                        if (!r)
                        snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
                                 bciphers[i].cipher, bciphers[i].mode);
                        if (!r)
-                               log_std("%11s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
+                               log_std("%12s  %4zub  %6.1f MiB/s  %6.1f MiB/s\n",
                                        cipher, bciphers[i].key_size*8, enc_mbr, dec_mbr);
                        else
                                        cipher, bciphers[i].key_size*8, enc_mbr, dec_mbr);
                        else
-                               log_std("%11s  %4db %12s %12s\n", cipher,
+                               log_std("%12s  %4zub %13s %13s\n", cipher,
                                        bciphers[i].key_size*8, _("N/A"), _("N/A"));
                }
                                        bciphers[i].key_size*8, _("N/A"), _("N/A"));
                }
+               if (skipped && skipped == i)
+                       r = -ENOTSUP;
        }
 
        }
 
+       if (r == -ENOTSUP) {
+               log_err(_("Required kernel crypto interface not available.\n"));
+#ifdef ENABLE_AF_ALG
+               log_err( _("Ensure you have algif_skcipher kernel module loaded.\n"));
+#endif
+       }
        return r;
 }
 
        return r;
 }
 
@@ -484,11 +636,11 @@ static int _read_mk(const char *file, char **key, int keysize)
 
        fd = open(file, O_RDONLY);
        if (fd == -1) {
 
        fd = open(file, O_RDONLY);
        if (fd == -1) {
-               log_err("Cannot read keyfile %s.\n", file);
+               log_err(_("Cannot read keyfile %s.\n"), file);
                goto fail;
        }
        if ((read(fd, *key, keysize) != keysize)) {
                goto fail;
        }
        if ((read(fd, *key, keysize) != keysize)) {
-               log_err("Cannot read %d bytes from keyfile %s.\n", keysize, file);
+               log_err(_("Cannot read %d bytes from keyfile %s.\n"), keysize, file);
                close(fd);
                goto fail;
        }
                close(fd);
                goto fail;
        }
@@ -500,7 +652,7 @@ fail:
        return -EINVAL;
 }
 
        return -EINVAL;
 }
 
-static int action_luksRepair(int arg __attribute__((unused)))
+static int action_luksRepair(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -513,7 +665,7 @@ static int action_luksRepair(int arg __attribute__((unused)))
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
        crypt_set_log_callback(cd, tool_log, NULL);
        if (r == 0) {
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
        crypt_set_log_callback(cd, tool_log, NULL);
        if (r == 0) {
-               log_verbose( _("No known problems detected for LUKS header.\n"));
+               log_verbose(_("No known problems detected for LUKS header.\n"));
                goto out;
        }
 
                goto out;
        }
 
@@ -526,7 +678,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksFormat(int arg __attribute__((unused)))
+static int action_luksFormat(void)
 {
        int r = -EINVAL, keysize;
        const char *header_device;
 {
        int r = -EINVAL, keysize;
        const char *header_device;
@@ -577,9 +729,9 @@ static int action_luksFormat(int arg __attribute__((unused)))
        else if (opt_urandom)
                crypt_set_rng_type(cd, CRYPT_RNG_URANDOM);
 
        else if (opt_urandom)
                crypt_set_rng_type(cd, CRYPT_RNG_URANDOM);
 
-       r = crypt_get_key(_("Enter LUKS passphrase: "), &password, &passwordLen,
+       r = tools_get_key(_("Enter passphrase: "), &password, &passwordLen,
                          opt_keyfile_offset, opt_keyfile_size, opt_key_file,
                          opt_keyfile_offset, opt_keyfile_size, opt_key_file,
-                         opt_timeout, _verify_passphrase(1), cd);
+                         opt_timeout, _verify_passphrase(1), 1, cd);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
@@ -591,6 +743,7 @@ static int action_luksFormat(int arg __attribute__((unused)))
 
        r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
                         opt_uuid, key, keysize, &params);
 
        r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
                         opt_uuid, key, keysize, &params);
+       check_signal(&r);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
@@ -605,21 +758,15 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksOpen(int arg __attribute__((unused)))
+static int action_open_luks(void)
 {
        struct crypt_device *cd = NULL;
        const char *data_device, *header_device, *activated_name;
        char *key = NULL;
 {
        struct crypt_device *cd = NULL;
        const char *data_device, *header_device, *activated_name;
        char *key = NULL;
-       uint32_t flags = 0;
+       uint32_t activate_flags = 0;
        int r, keysize;
 
        int r, keysize;
 
-       if (opt_header_device) {
-               header_device = uuid_or_device(opt_header_device);
-               data_device = action_argv[0];
-       } else {
-               header_device = uuid_or_device(action_argv[0]);
-               data_device = NULL;
-       }
+       header_device = uuid_or_device_header(&data_device);
 
        activated_name = opt_test_passphrase ? NULL : action_argv[1];
 
 
        activated_name = opt_test_passphrase ? NULL : action_argv[1];
 
@@ -646,11 +793,7 @@ static int action_luksOpen(int arg __attribute__((unused)))
        if (opt_iteration_time)
                crypt_set_iteration_time(cd, opt_iteration_time);
 
        if (opt_iteration_time)
                crypt_set_iteration_time(cd, opt_iteration_time);
 
-       if (opt_readonly)
-               flags |= CRYPT_ACTIVATE_READONLY;
-
-       if (opt_allow_discards)
-               flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+       _set_activation_flags(&activate_flags);
 
        if (opt_master_key_file) {
                keysize = crypt_get_volume_key_size(cd);
 
        if (opt_master_key_file) {
                keysize = crypt_get_volume_key_size(cd);
@@ -658,15 +801,15 @@ static int action_luksOpen(int arg __attribute__((unused)))
                if (r < 0)
                        goto out;
                r = crypt_activate_by_volume_key(cd, activated_name,
                if (r < 0)
                        goto out;
                r = crypt_activate_by_volume_key(cd, activated_name,
-                                                key, keysize, flags);
+                                                key, keysize, activate_flags);
        } else if (opt_key_file) {
                crypt_set_password_retry(cd, 1);
                r = crypt_activate_by_keyfile_offset(cd, activated_name,
                        opt_key_slot, opt_key_file, opt_keyfile_size,
        } else if (opt_key_file) {
                crypt_set_password_retry(cd, 1);
                r = crypt_activate_by_keyfile_offset(cd, activated_name,
                        opt_key_slot, opt_key_file, opt_keyfile_size,
-                       opt_keyfile_offset, flags);
+                       opt_keyfile_offset, activate_flags);
        } else
                r = crypt_activate_by_passphrase(cd, activated_name,
        } else
                r = crypt_activate_by_passphrase(cd, activated_name,
-                       opt_key_slot, NULL, 0, flags);
+                       opt_key_slot, NULL, 0, activate_flags);
 out:
        crypt_safe_free(key);
        crypt_free(cd);
 out:
        crypt_safe_free(key);
        crypt_free(cd);
@@ -687,9 +830,9 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
        if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !yesDialog(msg_last, NULL))
                return -EPERM;
 
        if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !yesDialog(msg_last, NULL))
                return -EPERM;
 
-       r = crypt_get_key(msg_pass, &password, &passwordLen,
+       r = tools_get_key(msg_pass, &password, &passwordLen,
                          keyfile_offset, keyfile_size, key_file, opt_timeout,
                          keyfile_offset, keyfile_size, key_file, opt_timeout,
-                         _verify_passphrase(0), cd);
+                         _verify_passphrase(0), 0, cd);
        if(r < 0)
                goto out;
 
        if(r < 0)
                goto out;
 
@@ -718,12 +861,12 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksKillSlot(int arg __attribute__((unused)))
+static int action_luksKillSlot(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        int r;
 
-       if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
@@ -747,7 +890,7 @@ static int action_luksKillSlot(int arg __attribute__((unused)))
        if (!opt_batch_mode) {
                r = verify_keyslot(cd, opt_key_slot,
                        _("This is the last keyslot. Device will become unusable after purging this key."),
        if (!opt_batch_mode) {
                r = verify_keyslot(cd, opt_key_slot,
                        _("This is the last keyslot. Device will become unusable after purging this key."),
-                       _("Enter any remaining LUKS passphrase: "),
+                       _("Enter any remaining passphrase: "),
                        opt_key_file, opt_keyfile_offset, opt_keyfile_size);
                if (r < 0)
                        goto out;
                        opt_key_file, opt_keyfile_offset, opt_keyfile_size);
                if (r < 0)
                        goto out;
@@ -759,14 +902,14 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksRemoveKey(int arg __attribute__((unused)))
+static int action_luksRemoveKey(void)
 {
        struct crypt_device *cd = NULL;
        char *password = NULL;
        size_t passwordLen;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        char *password = NULL;
        size_t passwordLen;
        int r;
 
-       if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
@@ -775,17 +918,18 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
-       r = crypt_get_key(_("Enter LUKS passphrase to be deleted: "),
+       r = tools_get_key(_("Enter passphrase to be deleted: "),
                      &password, &passwordLen,
                      opt_keyfile_offset, opt_keyfile_size, opt_key_file,
                      opt_timeout,
                      &password, &passwordLen,
                      opt_keyfile_offset, opt_keyfile_size, opt_key_file,
                      opt_timeout,
-                     _verify_passphrase(0),
+                     _verify_passphrase(0), 0,
                      cd);
        if(r < 0)
                goto out;
 
        r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT,
                                         password, passwordLen, 0);
                      cd);
        if(r < 0)
                goto out;
 
        r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT,
                                         password, passwordLen, 0);
+       check_signal(&r);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
@@ -807,14 +951,16 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksAddKey(int arg __attribute__((unused)))
+static int action_luksAddKey(void)
 {
        int r = -EINVAL, keysize = 0;
        char *key = NULL;
        const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
 {
        int r = -EINVAL, keysize = 0;
        char *key = NULL;
        const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
+       char *password = NULL, *password_new = NULL;
+       size_t password_size = 0, password_new_size = 0;
        struct crypt_device *cd = NULL;
 
        struct crypt_device *cd = NULL;
 
-       if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
@@ -833,43 +979,68 @@ static int action_luksAddKey(int arg __attribute__((unused)))
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
                        goto out;
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
                        goto out;
-               //FIXME: process keyfile arg
-               r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
-                                                   key, keysize, NULL, 0);
+
+               r = crypt_volume_key_verify(cd, key, keysize);
+               check_signal(&r);
+               if (r < 0)
+                       goto out;
+
+               r = tools_get_key(_("Enter new passphrase for key slot: "),
+                                 &password_new, &password_new_size,
+                                 opt_new_keyfile_offset, opt_new_keyfile_size,
+                                 opt_new_key_file, opt_timeout,
+                                 _verify_passphrase(1), 1, cd);
+               if (r < 0)
+                       goto out;
+
+               r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot, key, keysize,
+                                                   password_new, password_new_size);
        } else if (opt_key_file || opt_new_key_file) {
                r = crypt_keyslot_add_by_keyfile_offset(cd, opt_key_slot,
                        opt_key_file, opt_keyfile_size, opt_keyfile_offset,
                        opt_new_key_file, opt_new_keyfile_size, opt_new_keyfile_offset);
        } else {
        } else if (opt_key_file || opt_new_key_file) {
                r = crypt_keyslot_add_by_keyfile_offset(cd, opt_key_slot,
                        opt_key_file, opt_keyfile_size, opt_keyfile_offset,
                        opt_new_key_file, opt_new_keyfile_size, opt_new_keyfile_offset);
        } else {
+               r = tools_get_key(_("Enter any existing passphrase: "),
+                             &password, &password_size, 0, 0, NULL,
+                             opt_timeout, _verify_passphrase(0), 0, cd);
+
+               if (r < 0)
+                       goto out;
+
+               /* Check password before asking for new one */
+               r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT,
+                                                password, password_size, 0);
+               check_signal(&r);
+               if (r < 0)
+                       goto out;
+
+               r = tools_get_key(_("Enter new passphrase for key slot: "),
+                                 &password_new, &password_new_size, 0, 0, NULL,
+                                 opt_timeout, _verify_passphrase(1), 1, cd);
+               if (r < 0)
+                       goto out;
+
                r = crypt_keyslot_add_by_passphrase(cd, opt_key_slot,
                r = crypt_keyslot_add_by_passphrase(cd, opt_key_slot,
-                                                   NULL, 0, NULL, 0);
+                                                   password, password_size,
+                                                   password_new, password_new_size);
        }
 out:
        }
 out:
-       crypt_free(cd);
+       crypt_safe_free(password);
+       crypt_safe_free(password_new);
        crypt_safe_free(key);
        crypt_safe_free(key);
+       crypt_free(cd);
        return r;
 }
 
        return r;
 }
 
-static int _slots_full(struct crypt_device *cd)
-{
-       int i;
-
-       for (i = 0; i < crypt_keyslot_max(crypt_get_type(cd)); i++)
-               if (crypt_keyslot_status(cd, i) == CRYPT_SLOT_INACTIVE)
-                       return 0;
-       return 1;
-}
-
-static int action_luksChangeKey(int arg __attribute__((unused)))
+static int action_luksChangeKey(void)
 {
        const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
        struct crypt_device *cd = NULL;
 {
        const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
        struct crypt_device *cd = NULL;
-       char *vk = NULL, *password = NULL;
-       size_t passwordLen = 0;
-       size_t vk_size;
-       int new_key_slot, old_key_slot, r;
+       char *password = NULL, *password_new = NULL;
+       size_t password_size = 0, password_new_size = 0;
+       int r;
 
 
-       if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -878,82 +1049,49 @@ static int action_luksChangeKey(int arg __attribute__((unused)))
        if (opt_iteration_time)
                crypt_set_iteration_time(cd, opt_iteration_time);
 
        if (opt_iteration_time)
                crypt_set_iteration_time(cd, opt_iteration_time);
 
-       r = crypt_get_key(_("Enter LUKS passphrase to be changed: "),
-                     &password, &passwordLen,
+       r = tools_get_key(_("Enter passphrase to be changed: "),
+                     &password, &password_size,
                      opt_keyfile_offset, opt_keyfile_size, opt_key_file,
                      opt_keyfile_offset, opt_keyfile_size, opt_key_file,
-                     opt_timeout, _verify_passphrase(0), cd);
+                     opt_timeout, _verify_passphrase(0), 0, cd);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       vk_size = crypt_get_volume_key_size(cd);
-       vk = crypt_safe_alloc(vk_size);
-       if (!vk) {
-               r = -ENOMEM;
-               goto out;
-       }
-
-       r = crypt_volume_key_get(cd, opt_key_slot, vk, &vk_size,
-                                password, passwordLen);
-       if (r < 0) {
-               if (opt_key_slot != CRYPT_ANY_SLOT)
-                       log_err(_("No key available with this passphrase.\n"));
+       /* Check password before asking for new one */
+       r = crypt_activate_by_passphrase(cd, NULL, opt_key_slot,
+                                        password, password_size, 0);
+       check_signal(&r);
+       if (r < 0)
                goto out;
                goto out;
-       }
 
 
-       if (opt_key_slot != CRYPT_ANY_SLOT || _slots_full(cd)) {
-               log_dbg("Key slot %d is going to be overwritten (%s).",
-                       r, opt_key_slot != CRYPT_ANY_SLOT ?
-                       "explicit key slot specified" : "no free key slot");
-               old_key_slot = r;
-               new_key_slot = r;
-       } else {
-               log_dbg("Allocating new key slot.");
-               old_key_slot = r;
-               new_key_slot = CRYPT_ANY_SLOT;
-       }
-
-       crypt_safe_free(password);
-       password = NULL;
-       passwordLen = 0;
-       r = crypt_get_key(_("Enter new LUKS passphrase: "),
-                         &password, &passwordLen,
+       r = tools_get_key(_("Enter new passphrase: "),
+                         &password_new, &password_new_size,
                          opt_new_keyfile_offset, opt_new_keyfile_size,
                          opt_new_key_file,
                          opt_new_keyfile_offset, opt_new_keyfile_size,
                          opt_new_key_file,
-                         opt_timeout, _verify_passphrase(0), cd);
+                         opt_timeout, _verify_passphrase(1), 1, cd);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       if (new_key_slot == old_key_slot) {
-               (void)crypt_keyslot_destroy(cd, old_key_slot);
-               r = crypt_keyslot_add_by_volume_key(cd, new_key_slot,
-                                                   vk, vk_size,
-                                                   password, passwordLen);
-               if (r >= 0)
-                       log_verbose(_("Key slot %d changed.\n"), r);
-       } else {
-               r = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT,
-                                                   vk, vk_size,
-                                                   password, passwordLen);
-               if (r >= 0) {
-                       log_verbose(_("Replaced with key slot %d.\n"), r);
-                       r = crypt_keyslot_destroy(cd, old_key_slot);
-               }
-       }
-       if (r < 0)
-               log_err(_("Failed to swap new key slot.\n"));
+       r = crypt_keyslot_change_by_passphrase(cd, opt_key_slot, opt_key_slot,
+               password, password_size, password_new, password_new_size);
 out:
 out:
-       crypt_safe_free(vk);
        crypt_safe_free(password);
        crypt_safe_free(password);
+       crypt_safe_free(password_new);
        crypt_free(cd);
        return r;
 }
 
        crypt_free(cd);
        return r;
 }
 
-static int action_isLuks(int arg __attribute__((unused)))
+static int action_isLuks(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        int r;
 
-       if ((r = crypt_init(&cd, action_argv[0])))
+       /* FIXME: argc > max should be checked for other operations as well */
+       if (action_argc > 1) {
+               log_err(_("Only one device argument for isLuks operation is supported.\n"));
+               return -ENODEV;
+       }
+
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_log_callback(cd, quiet_log, NULL);
                goto out;
 
        crypt_set_log_callback(cd, quiet_log, NULL);
@@ -963,13 +1101,13 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksUUID(int arg __attribute__((unused)))
+static int action_luksUUID(void)
 {
        struct crypt_device *cd = NULL;
        const char *existing_uuid = NULL;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        const char *existing_uuid = NULL;
        int r;
 
-       if ((r = crypt_init(&cd, action_argv[0])))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
@@ -999,7 +1137,7 @@ static int luksDump_with_volume_key(struct crypt_device *cd)
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
        if (!yesDialog(
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
        if (!yesDialog(
-           _("LUKS header dump with volume key is sensitive information\n"
+           _("Header dump with volume key is sensitive information\n"
              "which allows access to encrypted partition without passphrase.\n"
              "This dump should be always stored encrypted on safe place."),
              NULL))
              "which allows access to encrypted partition without passphrase.\n"
              "This dump should be always stored encrypted on safe place."),
              NULL))
@@ -1010,14 +1148,15 @@ static int luksDump_with_volume_key(struct crypt_device *cd)
        if (!vk)
                return -ENOMEM;
 
        if (!vk)
                return -ENOMEM;
 
-       r = crypt_get_key(_("Enter LUKS passphrase: "), &password, &passwordLen,
+       r = tools_get_key(_("Enter passphrase: "), &password, &passwordLen,
                          opt_keyfile_offset, opt_keyfile_size, opt_key_file,
                          opt_keyfile_offset, opt_keyfile_size, opt_key_file,
-                         opt_timeout, 0, cd);
+                         opt_timeout, 0, 0, cd);
        if (r < 0)
                goto out;
 
        r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, vk, &vk_size,
                                 password, passwordLen);
        if (r < 0)
                goto out;
 
        r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, vk, &vk_size,
                                 password, passwordLen);
+       check_signal(&r);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
@@ -1042,12 +1181,12 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksDump(int arg __attribute__((unused)))
+static int action_luksDump(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        int r;
 
-       if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -1062,12 +1201,12 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksSuspend(int arg __attribute__((unused)))
+static int action_luksSuspend(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        int r;
 
-       r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
+       r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(opt_header_device));
        if (!r)
                r = crypt_suspend(cd, action_argv[0]);
 
        if (!r)
                r = crypt_suspend(cd, action_argv[0]);
 
@@ -1075,12 +1214,12 @@ static int action_luksSuspend(int arg __attribute__((unused)))
        return r;
 }
 
        return r;
 }
 
-static int action_luksResume(int arg __attribute__((unused)))
+static int action_luksResume(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 
 {
        struct crypt_device *cd = NULL;
        int r;
 
-       if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device)))
+       if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(opt_header_device))))
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
@@ -1098,7 +1237,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksBackup(int arg __attribute__((unused)))
+static int action_luksBackup(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -1108,7 +1247,7 @@ static int action_luksBackup(int arg __attribute__((unused)))
                return -EINVAL;
        }
 
                return -EINVAL;
        }
 
-       if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
@@ -1119,7 +1258,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksRestore(int arg __attribute__((unused)))
+static int action_luksRestore(void)
 {
        struct crypt_device *cd = NULL;
        int r = 0;
 {
        struct crypt_device *cd = NULL;
        int r = 0;
@@ -1129,7 +1268,7 @@ static int action_luksRestore(int arg __attribute__((unused)))
                return -EINVAL;
        }
 
                return -EINVAL;
        }
 
-       if ((r = crypt_init(&cd, action_argv[0])))
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
                goto out;
 
        crypt_set_confirm_callback(cd, yesDialog, NULL);
@@ -1139,6 +1278,108 @@ out:
        return r;
 }
 
        return r;
 }
 
+static int action_open(void)
+{
+       if (!opt_type)
+               return -EINVAL;
+
+       if (!strcmp(opt_type, "luks") || !strcmp(opt_type, "luks1")) {
+               if (action_argc < 2 && !opt_test_passphrase)
+                       goto args;
+               return action_open_luks();
+       } else if (!strcmp(opt_type, "plain")) {
+               if (action_argc < 2)
+                       goto args;
+               return action_open_plain();
+       } else if (!strcmp(opt_type, "loopaes")) {
+               if (action_argc < 2)
+                       goto args;
+               return action_open_loopaes();
+       } else if (!strcmp(opt_type, "tcrypt")) {
+               if (action_argc < 2 && !opt_test_passphrase)
+                       goto args;
+               return action_open_tcrypt();
+       }
+
+       log_err(_("Unrecognized metadata device type %s.\n"), opt_type);
+       return -EINVAL;
+args:
+       log_err(_("Command requires device and mapped name as arguments.\n"));
+       return -EINVAL;
+}
+
+static int action_luksErase(void)
+{
+       struct crypt_device *cd = NULL;
+       crypt_keyslot_info ki;
+       char *msg = NULL;
+       int i, r;
+
+       if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
+               goto out;
+
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
+
+       if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
+               goto out;
+
+       if(asprintf(&msg, _("This operation will erase all keyslots on device %s.\n"
+                           "Device will become unusable after this operation."),
+                           uuid_or_device_header(NULL)) == -1) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       if (!yesDialog(msg, NULL)) {
+               r = -EPERM;
+               goto out;
+       }
+
+       for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
+               ki = crypt_keyslot_status(cd, i);
+               if (ki == CRYPT_SLOT_ACTIVE || ki == CRYPT_SLOT_ACTIVE_LAST) {
+                       r = crypt_keyslot_destroy(cd, i);
+                       if (r < 0)
+                               goto out;
+               }
+       }
+out:
+       free(msg);
+       crypt_free(cd);
+       return r;
+}
+
+static struct action_type {
+       const char *type;
+       int (*handler)(void);
+       int required_action_argc;
+       int required_memlock;
+       const char *arg_desc;
+       const char *desc;
+} action_types[] = {
+       { "open",         action_open,         1, 1, N_("<device> [--type <type>] [<name>]"),N_("open device as mapping <name>") },
+       { "close",        action_close,        1, 1, N_("<name>"), N_("close device (remove mapping)") },
+       { "resize",       action_resize,       1, 1, N_("<name>"), N_("resize active device") },
+       { "status",       action_status,       1, 0, N_("<name>"), N_("show device status") },
+       { "benchmark",    action_benchmark,    0, 0, N_("<name>"), N_("benchmark cipher") },
+       { "repair",       action_luksRepair,   1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
+       { "erase",        action_luksErase ,   1, 1, N_("<device>"), N_("erase all keyslots (remove encryption key)") },
+       { "luksFormat",   action_luksFormat,   1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
+       { "luksAddKey",   action_luksAddKey,   1, 1, N_("<device> [<new key file>]"), N_("add key to LUKS device") },
+       { "luksRemoveKey",action_luksRemoveKey,1, 1, N_("<device> [<key file>]"), N_("removes supplied key or key file from LUKS device") },
+       { "luksChangeKey",action_luksChangeKey,1, 1, N_("<device> [<key file>]"), N_("changes supplied key or key file of LUKS device") },
+       { "luksKillSlot", action_luksKillSlot, 2, 1, N_("<device> <key slot>"), N_("wipes key with number <key slot> from LUKS device") },
+       { "luksUUID",     action_luksUUID,     1, 0, N_("<device>"), N_("print UUID of LUKS device") },
+       { "isLuks",       action_isLuks,       1, 0, N_("<device>"), N_("tests <device> for LUKS partition header") },
+       { "luksDump",     action_luksDump,     1, 1, N_("<device>"), N_("dump LUKS partition information") },
+       { "tcryptDump",   action_tcryptDump,   1, 1, N_("<device>"), N_("dump TCRYPT device information") },
+       { "luksSuspend",  action_luksSuspend,  1, 1, N_("<device>"), N_("Suspend LUKS device and wipe key (all IOs are frozen).") },
+       { "luksResume",   action_luksResume,   1, 1, N_("<device>"), N_("Resume suspended LUKS device.") },
+       { "luksHeaderBackup", action_luksBackup,1,1, N_("<device>"), N_("Backup LUKS device header and keyslots") },
+       { "luksHeaderRestore",action_luksRestore,1,1,N_("<device>"), N_("Restore LUKS device header and keyslots") },
+       {}
+};
+
 static void help(poptContext popt_context,
                 enum poptCallbackReason reason __attribute__((unused)),
                 struct poptOption *key,
 static void help(poptContext popt_context,
                 enum poptCallbackReason reason __attribute__((unused)),
                 struct poptOption *key,
@@ -1159,6 +1400,10 @@ static void help(poptContext popt_context,
                        log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
 
                log_std(_("\n"
                        log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
 
                log_std(_("\n"
+                         "You can also use old <action> syntax aliases:\n"
+                         "\topen: create (plainOpen), luksOpen, loopaesOpen, tcryptOpen\n"
+                         "\tclose: remove (plainClose), luksClose, loopaesClose, tcryptClose\n"));
+               log_std(_("\n"
                         "<name> is the device to create under %s\n"
                         "<device> is the encrypted device\n"
                         "<key slot> is the LUKS key slot number to modify\n"
                         "<name> is the device to create under %s\n"
                         "<device> is the encrypted device\n"
                         "<key slot> is the LUKS key slot number to modify\n"
@@ -1185,6 +1430,14 @@ static void help(poptContext popt_context,
                usage(popt_context, EXIT_SUCCESS, NULL, NULL);
 }
 
                usage(popt_context, EXIT_SUCCESS, NULL, NULL);
 }
 
+static void help_args(struct action_type *action, poptContext popt_context)
+{
+       char buf[128];
+
+       snprintf(buf, sizeof(buf), _("%s: requires %s as arguments"), action->type, action->arg_desc);
+       usage(popt_context, EXIT_FAILURE, buf, poptGetInvocationName(popt_context));
+}
+
 static int run_action(struct action_type *action)
 {
        int r;
 static int run_action(struct action_type *action)
 {
        int r;
@@ -1194,7 +1447,8 @@ static int run_action(struct action_type *action)
        if (action->required_memlock)
                crypt_memory_lock(NULL, 1);
 
        if (action->required_memlock)
                crypt_memory_lock(NULL, 1);
 
-       r = action->handler(action->arg);
+       set_int_handler(0);
+       r = action->handler();
 
        if (action->required_memlock)
                crypt_memory_lock(NULL, 0);
 
        if (action->required_memlock)
                crypt_memory_lock(NULL, 0);
@@ -1202,6 +1456,7 @@ static int run_action(struct action_type *action)
        /* Some functions returns keyslot # */
        if (r > 0)
                r = 0;
        /* Some functions returns keyslot # */
        if (r > 0)
                r = 0;
+       check_signal(&r);
 
        show_status(r);
        return translate_errno(r);
 
        show_status(r);
        return translate_errno(r);
@@ -1250,7 +1505,14 @@ int main(int argc, const char **argv)
                { "allow-discards",    '\0', POPT_ARG_NONE, &opt_allow_discards,        0, N_("Allow discards (aka TRIM) requests for device."), NULL },
                { "header",            '\0', POPT_ARG_STRING, &opt_header_device,       0, N_("Device or file with separated LUKS header."), NULL },
                { "test-passphrase",   '\0', POPT_ARG_NONE, &opt_test_passphrase,       0, N_("Do not activate device, just check passphrase."), NULL },
                { "allow-discards",    '\0', POPT_ARG_NONE, &opt_allow_discards,        0, N_("Allow discards (aka TRIM) requests for device."), NULL },
                { "header",            '\0', POPT_ARG_STRING, &opt_header_device,       0, N_("Device or file with separated LUKS header."), NULL },
                { "test-passphrase",   '\0', POPT_ARG_NONE, &opt_test_passphrase,       0, N_("Do not activate device, just check passphrase."), NULL },
-               { "hidden",            '\0', POPT_ARG_NONE, &opt_hidden,               0, N_("Use hidden header (hiden TCRYPT device) ."), NULL },
+               { "tcrypt-hidden",     '\0', POPT_ARG_NONE, &opt_tcrypt_hidden,         0, N_("Use hidden header (hidden TCRYPT device)."), NULL },
+               { "tcrypt-system",     '\0', POPT_ARG_NONE, &opt_tcrypt_system,         0, N_("Device is system TCRYPT drive (with bootloader)."), NULL },
+               { "tcrypt-backup",     '\0', POPT_ARG_NONE, &opt_tcrypt_backup,         0, N_("Use backup (secondary) TCRYPT header."), NULL },
+               { "veracrypt",         '\0', POPT_ARG_NONE, &opt_veracrypt,             0, N_("Scan also for VeraCrypt compatible device."), NULL },
+               { "type",               'M', POPT_ARG_STRING, &opt_type,                0, N_("Type of device metadata: luks, plain, loopaes, tcrypt."), NULL },
+               { "force-password",    '\0', POPT_ARG_NONE, &opt_force_password,        0, N_("Disable password quality check (if enabled)."), NULL },
+               { "perf-same_cpu_crypt",'\0', POPT_ARG_NONE, &opt_perf_same_cpu_crypt,  0, N_("Use dm-crypt same_cpu_crypt performance compatibility option."), NULL },
+               { "perf-submit_from_crypt_cpus",'\0', POPT_ARG_NONE, &opt_perf_submit_from_crypt_cpus,0,N_("Use dm-crypt submit_from_crypt_cpus performance compatibility option."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
                POPT_TABLEEND
        };
        poptContext popt_context;
@@ -1264,8 +1526,6 @@ int main(int argc, const char **argv)
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
 
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
 
-       crypt_fips_self_check(NULL);
-
        popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
        poptSetOtherOptionHelp(popt_context,
                               _("[OPTION...] <action> <action-specific>"));
        popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
        poptSetOtherOptionHelp(popt_context,
                               _("[OPTION...] <action> <action-specific>"));
@@ -1307,6 +1567,10 @@ int main(int argc, const char **argv)
        if (r < -1)
                usage(popt_context, EXIT_FAILURE, poptStrerror(r),
                      poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
        if (r < -1)
                usage(popt_context, EXIT_FAILURE, poptStrerror(r),
                      poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
+
+       if (crypt_fips_mode())
+               crypt_log(NULL, CRYPT_LOG_VERBOSE, _("Running in FIPS mode.\n"));
+
        if (opt_version_mode) {
                log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
                poptFreeContext(popt_context);
        if (opt_version_mode) {
                log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
                poptFreeContext(popt_context);
@@ -1316,12 +1580,6 @@ int main(int argc, const char **argv)
        if (!(aname = poptGetArg(popt_context)))
                usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
                      poptGetInvocationName(popt_context));
        if (!(aname = poptGetArg(popt_context)))
                usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
                      poptGetInvocationName(popt_context));
-       for(action = action_types; action->type; action++)
-               if (strcmp(action->type, aname) == 0)
-                       break;
-       if (!action->type)
-               usage(popt_context, EXIT_FAILURE, _("Unknown action."),
-                     poptGetInvocationName(popt_context));
 
        action_argc = 0;
        action_argv = poptGetArgs(popt_context);
 
        action_argc = 0;
        action_argv = poptGetArgs(popt_context);
@@ -1333,43 +1591,77 @@ int main(int argc, const char **argv)
        while(action_argv[action_argc] != NULL)
                action_argc++;
 
        while(action_argv[action_argc] != NULL)
                action_argc++;
 
-       if(action_argc < action->required_action_argc) {
-               char buf[128];
-               snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
-               usage(popt_context, EXIT_FAILURE, buf,
-                     poptGetInvocationName(popt_context));
+       /* Handle aliases */
+       if (!strcmp(aname, "create")) {
+               /* create command had historically switched arguments */
+               if (action_argv[0] && action_argv[1]) {
+                       const char *tmp = action_argv[0];
+                       action_argv[0] = action_argv[1];
+                       action_argv[1] = tmp;
+               }
+               aname = "open";
+               opt_type = "plain";
+       } else if (!strcmp(aname, "plainOpen")) {
+               aname = "open";
+               opt_type = "plain";
+       } else if (!strcmp(aname, "luksOpen")) {
+               aname = "open";
+               opt_type = "luks";
+       } else if (!strcmp(aname, "loopaesOpen")) {
+               aname = "open";
+               opt_type = "loopaes";
+       } else if (!strcmp(aname, "tcryptOpen")) {
+               aname = "open";
+               opt_type = "tcrypt";
+       } else if (!strcmp(aname, "tcryptDump")) {
+               opt_type = "tcrypt";
+       } else if (!strcmp(aname, "remove") ||
+                  !strcmp(aname, "plainClose") ||
+                  !strcmp(aname, "luksClose") ||
+                  !strcmp(aname, "loopaesClose") ||
+                  !strcmp(aname, "tcryptClose")) {
+               aname = "close";
+       } else if (!strcmp(aname, "luksErase")) {
+               aname = "erase";
+               opt_type = "luks";
        }
 
        }
 
+       for(action = action_types; action->type; action++)
+               if (strcmp(action->type, aname) == 0)
+                       break;
+
+       if (!action->type)
+               usage(popt_context, EXIT_FAILURE, _("Unknown action."),
+                     poptGetInvocationName(popt_context));
+
+       if (action_argc < action->required_action_argc)
+               help_args(action, popt_context);
+
        /* FIXME: rewrite this from scratch */
 
        /* FIXME: rewrite this from scratch */
 
-       if (opt_shared && strcmp(aname, "create"))
+       if (opt_shared && (strcmp(aname, "open") || strcmp(opt_type, "plain")) )
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --shared is allowed only for create operation.\n"),
+                     _("Option --shared is allowed only for open of plain device.\n"),
                      poptGetInvocationName(popt_context));
 
                      poptGetInvocationName(popt_context));
 
-       if (opt_allow_discards &&
-           strcmp(aname, "luksOpen") &&
-           strcmp(aname, "create") &&
-           strcmp(aname, "loopaesOpen"))
+       if (opt_allow_discards && strcmp(aname, "open"))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --allow-discards is allowed only for luksOpen, loopaesOpen and create operation.\n"),
+                     _("Option --allow-discards is allowed only for open operation.\n"),
                      poptGetInvocationName(popt_context));
 
        if (opt_key_size &&
           strcmp(aname, "luksFormat") &&
                      poptGetInvocationName(popt_context));
 
        if (opt_key_size &&
           strcmp(aname, "luksFormat") &&
-          strcmp(aname, "create") &&
-          strcmp(aname, "loopaesOpen") &&
+          strcmp(aname, "open") &&
           strcmp(aname, "benchmark"))
                usage(popt_context, EXIT_FAILURE,
           strcmp(aname, "benchmark"))
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --key-size is allowed only for luksFormat, create, loopaesOpen and benchmark.\n"
+                     _("Option --key-size is allowed only for luksFormat, open and benchmark.\n"
                        "To limit read from keyfile use --keyfile-size=(bytes)."),
                      poptGetInvocationName(popt_context));
 
                        "To limit read from keyfile use --keyfile-size=(bytes)."),
                      poptGetInvocationName(popt_context));
 
-       if (opt_test_passphrase &&
-          strcmp(aname, "luksOpen") &&
-          strcmp(aname, "tcryptOpen"))
+       if (opt_test_passphrase && (strcmp(aname, "open") ||
+           (strcmp(opt_type, "luks") && strcmp(opt_type, "tcrypt"))))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --test-passphrase is allowed only for luksOpen and tcryptOpen.\n"),
+                     _("Option --test-passphrase is allowed only for open of LUKS and TCRYPT devices.\n"),
                      poptGetInvocationName(popt_context));
 
        if (opt_key_size % 8)
                      poptGetInvocationName(popt_context));
 
        if (opt_key_size % 8)
@@ -1415,19 +1707,32 @@ int main(int argc, const char **argv)
                usage(popt_context, EXIT_FAILURE, _("Option --align-payload is allowed only for luksFormat."),
                      poptGetInvocationName(popt_context));
 
                usage(popt_context, EXIT_FAILURE, _("Option --align-payload is allowed only for luksFormat."),
                      poptGetInvocationName(popt_context));
 
-       if (opt_skip && strcmp(aname, "create") && strcmp(aname, "loopaesOpen"))
+       if (opt_skip && (strcmp(aname, "open") ||
+           (strcmp(opt_type, "plain") && strcmp(opt_type, "loopaes"))))
+               usage(popt_context, EXIT_FAILURE,
+               _("Option --skip is supported only for open of plain and loopaes devices.\n"),
+               poptGetInvocationName(popt_context));
+
+       if (opt_offset && (strcmp(aname, "open") ||
+           (strcmp(opt_type, "plain") && strcmp(opt_type, "loopaes"))))
+               usage(popt_context, EXIT_FAILURE,
+               _("Option --offset is supported only for open of plain and loopaes devices.\n"),
+               poptGetInvocationName(popt_context));
+
+       if ((opt_tcrypt_hidden || opt_tcrypt_system || opt_tcrypt_backup) && strcmp(aname, "tcryptDump") &&
+           (strcmp(aname, "open") || strcmp(opt_type, "tcrypt")))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-               _("Option --skip is supported only for create and loopaesOpen commands.\n"),
+               _("Option --tcrypt-hidden, --tcrypt-system or --tcrypt-backup is supported only for TCRYPT device.\n"),
                poptGetInvocationName(popt_context));
 
                poptGetInvocationName(popt_context));
 
-       if (opt_offset && strcmp(aname, "create") && strcmp(aname, "loopaesOpen"))
+       if (opt_tcrypt_hidden && opt_allow_discards)
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-               _("Option --offset is supported only for create and loopaesOpen commands.\n"),
+               _("Option --tcrypt-hidden cannot be combined with --allow-discards.\n"),
                poptGetInvocationName(popt_context));
 
                poptGetInvocationName(popt_context));
 
-       if (opt_hidden && strcmp(aname, "tcryptOpen"))
+       if (opt_veracrypt && strcmp(opt_type, "tcrypt"))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-               _("Option --hidden is supported only for tcryptOpen command.\n"),
+               _("Option --veracrypt is supported only for TCRYPT device type.\n"),
                poptGetInvocationName(popt_context));
 
        if (opt_debug) {
                poptGetInvocationName(popt_context));
 
        if (opt_debug) {