Handle kernel crypto api init failure better.
[platform/upstream/cryptsetup.git] / src / cryptsetup.c
index 32aebf6..31896f2 100644 (file)
 static const char *opt_cipher = NULL;
 static const char *opt_hash = NULL;
 static int opt_verify_passphrase = 0;
+
 static const char *opt_key_file = NULL;
+static int opt_keyfiles_count = 0;
+static const char *opt_keyfiles[MAX_KEYFILES];
+
 static const char *opt_master_key_file = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
@@ -40,7 +44,7 @@ static uint64_t opt_offset = 0;
 static uint64_t opt_skip = 0;
 static int opt_skip_valid = 0;
 static int opt_readonly = 0;
-static int opt_iteration_time = 1000;
+static int opt_iteration_time = DEFAULT_LUKS1_ITER_TIME;
 static int opt_version_mode = 0;
 static int opt_timeout = 0;
 static int opt_tries = 3;
@@ -51,14 +55,17 @@ static int opt_dump_master_key = 0;
 static int opt_shared = 0;
 static int opt_allow_discards = 0;
 static int opt_test_passphrase = 0;
+static int opt_hidden = 0;
 
 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);
@@ -74,6 +81,8 @@ 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 int action_tcryptDump(int arg);
 
 static struct action_type {
        const char *type;
@@ -88,6 +97,7 @@ static struct action_type {
        { "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>") },
@@ -105,6 +115,8 @@ static struct action_type {
        { "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>") },
+       { "tcryptDump", action_tcryptDump,      0, 1, 1, N_("<device>"), N_("dump TCRYPT device information") },
        { NULL, NULL, 0, 0, 0, NULL, NULL }
 };
 
@@ -249,6 +261,84 @@ out:
        return r;
 }
 
+static int action_tcryptOpen(int arg __attribute__((unused)))
+{
+       struct crypt_device *cd = NULL;
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+               .flags = CRYPT_TCRYPT_LEGACY_MODES,
+       };
+       const char *activated_name;
+       uint32_t flags = 0;
+       int r;
+
+       activated_name = opt_test_passphrase ? NULL : action_argv[1];
+
+       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);
+       if (r < 0)
+               goto out;
+
+       if (opt_hidden)
+               params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+       r = crypt_load(cd, CRYPT_TCRYPT, &params);
+       if (r < 0)
+               goto out;
+
+       if (opt_readonly)
+               flags |= CRYPT_ACTIVATE_READONLY;
+
+       if (activated_name)
+               r = crypt_activate_by_volume_key(cd, activated_name, NULL, 0, flags);
+out:
+       crypt_free(cd);
+       crypt_safe_free(CONST_CAST(char*)params.passphrase);
+       return r;
+}
+
+static int action_tcryptDump(int arg __attribute__((unused)))
+{
+       struct crypt_device *cd = NULL;
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+               .flags = CRYPT_TCRYPT_LEGACY_MODES,
+       };
+       int r;
+
+       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);
+       if (r < 0)
+               goto out;
+
+       if (opt_hidden)
+               params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+       r = crypt_load(cd, CRYPT_TCRYPT, &params);
+       if (r < 0)
+               goto out;
+
+       r = crypt_dump(cd);
+out:
+       crypt_free(cd);
+       crypt_safe_free(CONST_CAST(char*)params.passphrase);
+       return r;
+}
+
 static int action_remove(int arg __attribute__((unused)))
 {
        struct crypt_device *cd = NULL;
@@ -345,6 +435,89 @@ out:
        return r;
 }
 
+static int action_benchmark(int arg __attribute__((unused)))
+{
+       static struct {
+               char *cipher;
+               char *mode;
+               size_t key_size;
+               size_t iv_size;
+       } bciphers[] = {
+               { "aes",     "cbc", 16, 16 },
+               { "serpent", "cbc", 16, 16 },
+               { "twofish", "cbc", 16, 16 },
+               { "aes",     "cbc", 32, 16 },
+               { "serpent", "cbc", 32, 16 },
+               { "twofish", "cbc", 32, 16 },
+               { "aes",     "xts", 32, 16 },
+               { "serpent", "xts", 32, 16 },
+               { "twofish", "xts", 32, 16 },
+               { "aes",     "xts", 64, 16 },
+               { "serpent", "xts", 64, 16 },
+               { "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";
+       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;
+       char *c;
+       int i, r;
+
+       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"));
+                       return r;
+               }
+               if ((c  = strchr(cipher_mode, '-')))
+                       *c = '\0';
+
+               /* FIXME: not really clever :) */
+               if (strstr(cipher, "des"))
+                       iv_size = 8;
+
+               r = crypt_benchmark(NULL, cipher, cipher_mode,
+                                   key_size / 8, iv_size, buffer_size,
+                                   &enc_mbr, &dec_mbr);
+               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 if (r == -ENOTSUP)
+                       log_err(_("Cipher %s is not available.\n"), opt_cipher);
+       } else {
+               for (i = 0; bciphers[i].cipher; i++) {
+                       r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
+                                           bciphers[i].key_size, bciphers[i].iv_size,
+                                           buffer_size, &enc_mbr, &dec_mbr);
+                       if (r == -ENOENT)
+                               break;
+                       if (i == 0)
+                               log_std("%s", header);
+
+                       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",
+                                       cipher, bciphers[i].key_size*8, enc_mbr, dec_mbr);
+                       else
+                               log_std("%11s  %4db %12s %12s\n", cipher,
+                                       bciphers[i].key_size*8, _("N/A"), _("N/A"));
+               }
+       }
+
+       if (r == -ENOENT)
+               log_err( _("Required kernel crypto interface is not available.\n"
+                          "Ensure you have af_skcipher kernel module loaded.\n"));
+       return r;
+}
+
 static int _read_mk(const char *file, char **key, int keysize)
 {
        int fd;
@@ -1036,10 +1209,12 @@ static void help(poptContext popt_context,
                         "<key file> optional key file for the new key for luksAddKey action\n"),
                        crypt_get_dir());
 
-               log_std(_("\nDefault compiled-in keyfile parameters:\n"
+               log_std(_("\nDefault compiled-in key and passphrase parameters:\n"
                         "\tMaximum keyfile size: %dkB, "
-                        "Maximum interactive passphrase length %d (characters)\n"),
-                        DEFAULT_KEYFILE_SIZE_MAXKB, DEFAULT_PASSPHRASE_SIZE_MAX);
+                        "Maximum interactive passphrase length %d (characters)\n"
+                        "Default PBKDF2 iteration time for LUKS: %d (ms)\n"),
+                        DEFAULT_KEYFILE_SIZE_MAXKB, DEFAULT_PASSPHRASE_SIZE_MAX,
+                        DEFAULT_LUKS1_ITER_TIME);
 
                log_std(_("\nDefault compiled-in device cipher parameters:\n"
                         "\tloop-AES: %s, Key %d bits\n"
@@ -1093,7 +1268,7 @@ int main(int argc, const char **argv)
                { "cipher",            'c',  POPT_ARG_STRING, &opt_cipher,              0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
                { "hash",              'h',  POPT_ARG_STRING, &opt_hash,                0, N_("The hash used to create the encryption key from the passphrase"), NULL },
                { "verify-passphrase", 'y',  POPT_ARG_NONE, &opt_verify_passphrase,     0, N_("Verifies the passphrase by asking for it twice"), NULL },
-               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            0, N_("Read the key from a file."), NULL },
+               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            5, N_("Read the key from a file."), NULL },
                { "master-key-file",  '\0',  POPT_ARG_STRING, &opt_master_key_file,     0, N_("Read the volume (master) key from file."), NULL },
                { "dump-master-key",  '\0',  POPT_ARG_NONE, &opt_dump_master_key,       0, N_("Dump volume (master) key instead of keyslots info."), NULL },
                { "key-size",          's',  POPT_ARG_INT, &opt_key_size,               0, N_("The size of the encryption key"), N_("BITS") },
@@ -1119,13 +1294,13 @@ 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 },
+               { "hidden",            '\0', POPT_ARG_NONE, &opt_hidden,               0, N_("Use hidden header (hiden TCRYPT device) ."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
        struct action_type *action;
        const char *aname;
        int r;
-       const char *null_action_argv[] = {NULL};
 
        crypt_set_log_callback(NULL, tool_log, NULL);
 
@@ -1143,6 +1318,12 @@ int main(int argc, const char **argv)
                unsigned long long ull_value;
                char *endp;
 
+               if (r == 5) {
+                       if (opt_keyfiles_count < MAX_KEYFILES)
+                               opt_keyfiles[opt_keyfiles_count++] = poptGetOptArg(popt_context);
+                       continue;
+               }
+
                errno = 0;
                ull_value = strtoull(popt_tmp, &endp, 0);
                if (*endp || !*popt_tmp ||
@@ -1221,16 +1402,18 @@ int main(int argc, const char **argv)
        if (opt_key_size &&
           strcmp(aname, "luksFormat") &&
           strcmp(aname, "create") &&
-          strcmp(aname, "loopaesOpen"))
+          strcmp(aname, "loopaesOpen") &&
+          strcmp(aname, "benchmark"))
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --key-size is allowed only for luksFormat, create and loopaesOpen.\n"
+                     _("Option --key-size is allowed only for luksFormat, create, loopaesOpen and benchmark.\n"
                        "To limit read from keyfile use --keyfile-size=(bytes)."),
                      poptGetInvocationName(popt_context));
 
        if (opt_test_passphrase &&
-          strcmp(aname, "luksOpen"))
+          strcmp(aname, "luksOpen") &&
+          strcmp(aname, "tcryptOpen"))
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --test-passphrase is allowed only for luksOpen.\n"),
+                     _("Option --test-passphrase is allowed only for luksOpen and tcryptOpen.\n"),
                      poptGetInvocationName(popt_context));
 
        if (opt_key_size % 8)
@@ -1286,6 +1469,11 @@ int main(int argc, const char **argv)
                _("Option --offset is supported only for create and loopaesOpen commands.\n"),
                poptGetInvocationName(popt_context));
 
+       if (opt_hidden && strcmp(aname, "tcryptOpen") && strcmp(aname, "tcryptDump"))
+               usage(popt_context, EXIT_FAILURE,
+               _("Option --hidden is supported only for TCRYPT commands.\n"),
+               poptGetInvocationName(popt_context));
+
        if (opt_debug) {
                opt_verbose = 1;
                crypt_set_debug_level(-1);