From 9a798a766e99c212827f9a16feebf830d50b6c5a Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Mon, 6 Feb 2017 22:45:02 +0100 Subject: [PATCH] support PIM parameter for VeraCrypt compatible devices This patch adds the --veracrypt-pim=INT and --veracrypt-query-pim command- line parameters to support specification of or being queried for a custom Personal Iteration Multiplier respectively. This affects the number of iterations for key derivation from the entered password. The manpage is also updated accordingly. Fixes Issue #307. --- lib/libcryptsetup.h | 1 + lib/setup.c | 2 ++ lib/tcrypt/tcrypt.c | 8 ++++++ man/cryptsetup.8 | 13 +++++++++- src/cryptsetup.c | 63 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 80bbf5c8..76a3e7ec 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -338,6 +338,7 @@ struct crypt_params_tcrypt { const char *mode; /**< cipher block mode */ size_t key_size; /**< key size in bytes (the whole chain) */ uint32_t flags; /**< CRYPT_TCRYPT* flags */ + uint32_t veracrypt_pim; /**< VeraCrypt Personal Iteration Multiplier */ }; /** Include legacy modes when scanning for header */ diff --git a/lib/setup.c b/lib/setup.c index 1dca99b2..72cf4a6f 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -82,6 +82,7 @@ struct crypt_device { char cipher[MAX_CIPHER_LEN]; char cipher_mode[MAX_CIPHER_LEN]; unsigned int key_size; + unsigned int veracrypt_pim; } none; } u; @@ -571,6 +572,7 @@ static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcryp cd->u.tcrypt.params.passphrase_size = 0; cd->u.tcrypt.params.keyfiles = NULL; cd->u.tcrypt.params.keyfiles_count = 0; + cd->u.tcrypt.params.veracrypt_pim = 0; if (r < 0) return r; diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index 254dd1ba..a873091d 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -531,6 +531,14 @@ static int TCRYPT_init_hdr(struct crypt_device *cd, continue; if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt) continue; + if ((params->flags & CRYPT_TCRYPT_VERA_MODES) && params->veracrypt_pim) { + /* adjust iterations to given PIM cmdline parameter */ + if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) + tcrypt_kdf[i].iterations = params->veracrypt_pim * 2048; + else + tcrypt_kdf[i].iterations = 15000 + (params->veracrypt_pim * 1000); + } + /* Derive header key */ log_dbg("TCRYPT: trying KDF: %s-%s-%d.", tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations); diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 index b3cce841..a3e54891 100644 --- a/man/cryptsetup.8 +++ b/man/cryptsetup.8 @@ -450,11 +450,22 @@ Cryptsetup should recognize all header variants, except legacy cipher chains using LRW encryption mode with 64 bits encryption block (namely Blowfish in LRW mode is not recognized, this is limitation of kernel crypto API). -To recognize VeraCrypt device use \fB\-\-veracrypt\fR option. +To recognize a VeraCrypt device use the \fB\-\-veracrypt\fR option. VeraCrypt is just extension of TrueCrypt header with increased iteration count so unlocking can take quite a lot of time (in comparison with TCRYPT device). +To open a VeraCrypt device with a custom Personal Iteration Multiplier (PIM) +value, \fBadditionally to --veracrypt \fR use either the +\fB--veracrypt-pim=\fR option to directly specify the PIM on the command- +line or use \fB--veracrypt-query-pim\fR to be prompted for the PIM. + +The PIM value affects the number of iterations applied during key derivation. Please refer to +\fBhttps://veracrypt.codeplex.com/wikipage?title=Personal%20Iterations%20Multiplier%20(PIM)\fR +for more detailed information. + + + \fBNOTE:\fR Activation with \fBtcryptOpen\fR is supported only for cipher chains using LRW or XTS encryption modes. diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 2d6ddaf0..f8aa499d 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -65,6 +65,8 @@ static int opt_tcrypt_hidden = 0; static int opt_tcrypt_system = 0; static int opt_tcrypt_backup = 0; static int opt_veracrypt = 0; +static int opt_veracrypt_pim = -1; +static int opt_veracrypt_query_pim = 0; static const char **action_argv; static int action_argc; @@ -249,6 +251,38 @@ static int tcrypt_load(struct crypt_device *cd, struct crypt_params_tcrypt *para if (r < 0) continue; + if (opt_veracrypt_query_pim) { + char *tmp_pim_nptr = NULL; + char *tmp_pim_end = " "; + size_t tmp_pim_size = 0; + unsigned long int tmp_pim_ul = 0; + + r = tools_get_key(_("Enter VeraCrypt PIM: "), + CONST_CAST(char**)&tmp_pim_nptr, + &tmp_pim_size, 0, 0, opt_keyfile_stdin, opt_timeout, + _verify_passphrase(0), 0, cd); + if (r < 0) + continue; + + tmp_pim_ul = strtoul(tmp_pim_nptr, &tmp_pim_end, 10); + if (*tmp_pim_nptr == '\0' || *tmp_pim_end != '\0') { + log_err(_("Invalid PIM value: parse error\n")); + r = -EINVAL; + } else if (tmp_pim_ul == 0) { + log_err(_("Invalid PIM value: 0\n")); + r = -EINVAL; + } else if (tmp_pim_ul > ((1L << (CHAR_BIT * sizeof(params->veracrypt_pim))) - 1)) { + log_err(_("Invalid PIM value: outside of range\n")); + r = -ERANGE; + } + crypt_safe_free(CONST_CAST(char*)tmp_pim_nptr); + if (r < 0) + continue; + + params->veracrypt_pim = tmp_pim_ul; + tmp_pim_ul= 0; + } + if (opt_tcrypt_hidden) params->flags |= CRYPT_TCRYPT_HIDDEN_HEADER; @@ -271,7 +305,7 @@ static int tcrypt_load(struct crypt_device *cd, struct crypt_params_tcrypt *para params->passphrase_size = 0; } check_signal(&r); - } while (r == -EPERM && (--tries > 0)); + } while ((r == -EPERM || r == -EINVAL || r == -ERANGE) && (--tries > 0)); /* Report wrong passphrase if at least one try failed */ if (eperm && r == -EPIPE) @@ -288,6 +322,7 @@ static int action_open_tcrypt(void) .keyfiles_count = opt_keyfiles_count, .flags = CRYPT_TCRYPT_LEGACY_MODES | (opt_veracrypt ? CRYPT_TCRYPT_VERA_MODES : 0), + .veracrypt_pim = (opt_veracrypt_pim > 0) ? opt_veracrypt_pim : 0, }; const char *activated_name; uint32_t activate_flags = 0; @@ -1524,6 +1559,8 @@ int main(int argc, const char **argv) { "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 }, + { "veracrypt-pim", '\0', POPT_ARG_INT, &opt_veracrypt_pim, 0, N_("Personal Iteration Multiplier for for VeraCrypt compatible device."), NULL }, + { "veracrypt-query-pim", '\0', POPT_ARG_NONE, &opt_veracrypt_query_pim, 0, N_("Query Personal Iteration Multiplier for 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 }, @@ -1755,6 +1792,30 @@ int main(int argc, const char **argv) _("Option --veracrypt is supported only for TCRYPT device type.\n"), poptGetInvocationName(popt_context)); + if (opt_veracrypt_pim != -1) { + if (opt_veracrypt_pim < -1) { + usage(popt_context, EXIT_FAILURE, + _("Invalid argument for parameter --veracrypt-pim supplied.\n"), + poptGetInvocationName(popt_context)); + } else if (!opt_veracrypt) { + usage(popt_context, EXIT_FAILURE, + _("Option --veracrypt-pim is supported only for VeraCrypt compatible devices.\n"), + poptGetInvocationName(popt_context)); + } + } + + if (opt_veracrypt_query_pim) { + if (!opt_veracrypt) { + usage(popt_context, EXIT_FAILURE, + _("Option --veracrypt-query-pim is supported only for VeraCrypt compatible devices.\n"), + poptGetInvocationName(popt_context)); + } else if (opt_veracrypt_pim != -1) { + usage(popt_context, EXIT_FAILURE, + _("The options --veracrypt-pim and --veracrypt-query-pim are mutually exclusive.\n"), + poptGetInvocationName(popt_context)); + } + } + if (opt_debug) { opt_verbose = 1; crypt_set_debug_level(-1);