diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 4949b56a..db8beb0d 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -405,7 +405,7 @@ struct crypt_params_tcrypt { uint32_t flags; /**< CRYPT_TCRYPT* flags */ }; -/** Include legacy modes ehn scannig for header*/ +/** Include legacy modes for header*/ #define CRYPT_TCRYPT_LEGACY_MODES (1 << 0) /** Try to load hidden header (describing hidden device) */ #define CRYPT_TCRYPT_HIDDEN_HEADER (1 << 1) @@ -413,6 +413,8 @@ struct crypt_params_tcrypt { #define CRYPT_TCRYPT_BACKUP_HEADER (1 << 2) /** Device contains encrypted system (with boot loader) */ #define CRYPT_TCRYPT_SYSTEM_HEADER (1 << 3) +/** Include Veracrypt modes for header*/ +#define CRYPT_TCRYPT_VERA_MODES (1 << 4) /** @} */ diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index eca9302c..d49e196c 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -1,8 +1,8 @@ /* - * TCRYPT (TrueCrypt-compatible) volume handling + * TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling * * Copyright (C) 2012, Red Hat, Inc. All rights reserved. - * Copyright (C) 2012-2014, Milan Broz + * Copyright (C) 2012-2015, Milan Broz * * This file is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,16 +33,23 @@ /* TCRYPT PBKDF variants */ static struct { unsigned int legacy:1; + unsigned int veracrypt:1; const char *name; const char *hash; unsigned int iterations; } tcrypt_kdf[] = { - { 0, "pbkdf2", "ripemd160", 2000 }, - { 0, "pbkdf2", "ripemd160", 1000 }, - { 0, "pbkdf2", "sha512", 1000 }, - { 0, "pbkdf2", "whirlpool", 1000 }, - { 1, "pbkdf2", "sha1", 2000 }, - { 0, NULL, NULL, 0 } + { 0, 0, "pbkdf2", "ripemd160", 2000 }, + { 0, 0, "pbkdf2", "ripemd160", 1000 }, + { 0, 0, "pbkdf2", "sha512", 1000 }, + { 0, 0, "pbkdf2", "whirlpool", 1000 }, + { 1, 0, "pbkdf2", "sha1", 2000 }, + { 0, 1, "pbkdf2", "sha512", 500000 }, + { 0, 1, "pbkdf2", "whirlpool", 500000 }, + { 0, 1, "pbkdf2", "sha256", 500000 }, // VeraCrypt 1.0f + { 0, 1, "pbkdf2", "sha256", 200000 }, // boot only + { 0, 1, "pbkdf2", "ripemd160", 655331 }, + { 0, 1, "pbkdf2", "ripemd160", 327661 }, // boot only + { 0, 0, NULL, NULL, 0 } }; struct tcrypt_alg { @@ -196,7 +203,7 @@ static int TCRYPT_hdr_from_disk(struct tcrypt_phdr *hdr, /* Convert header to cpu format */ hdr->d.version = be16_to_cpu(hdr->d.version); - hdr->d.version_tc = le16_to_cpu(hdr->d.version_tc); + hdr->d.version_tc = be16_to_cpu(hdr->d.version_tc); hdr->d.keys_crc32 = be32_to_cpu(hdr->d.keys_crc32); @@ -393,13 +400,13 @@ out: } static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, - const char *key, int legacy_modes) + const char *key, uint32_t flags) { struct tcrypt_phdr hdr2; int i, j, r = -EINVAL; for (i = 0; tcrypt_cipher[i].chain_count; i++) { - if (!legacy_modes && tcrypt_cipher[i].legacy) + if (!(flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_cipher[i].legacy) continue; log_dbg("TCRYPT: trying cipher %s-%s", tcrypt_cipher[i].long_name, tcrypt_cipher[i].mode); @@ -431,6 +438,13 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, r = i; break; } + if ((flags & CRYPT_TCRYPT_VERA_MODES) && + !strncmp(hdr2.d.magic, VCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) { + log_dbg("TCRYPT: Signature magic detected (Veracrypt)."); + memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN); + r = i; + break; + } r = -EPERM; } @@ -485,7 +499,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd, size_t passphrase_size; char *key; unsigned int i, skipped = 0; - int r = -EPERM, legacy_modes; + int r = -EPERM; if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN)) return -ENOMEM; @@ -512,9 +526,10 @@ static int TCRYPT_init_hdr(struct crypt_device *cd, for (i = 0; i < params->passphrase_size; i++) pwd[i] += params->passphrase[i]; - legacy_modes = params->flags & CRYPT_TCRYPT_LEGACY_MODES ? 1 : 0; for (i = 0; tcrypt_kdf[i].name; i++) { - if (!legacy_modes && tcrypt_kdf[i].legacy) + if (!(params->flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_kdf[i].legacy) + continue; + if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt) continue; /* Derive header key */ log_dbg("TCRYPT: trying KDF: %s-%s-%d.", @@ -533,7 +548,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd, break; /* Decrypt header */ - r = TCRYPT_decrypt_hdr(cd, hdr, key, legacy_modes); + r = TCRYPT_decrypt_hdr(cd, hdr, key, params->flags); if (r == -ENOENT) { skipped++; r = -EPERM; @@ -553,10 +568,11 @@ static int TCRYPT_init_hdr(struct crypt_device *cd, r = TCRYPT_hdr_from_disk(hdr, params, i, r); if (!r) { - log_dbg("TCRYPT: Header version: %d, req. %d, sector %d" + log_dbg("TCRYPT: Magic: %s, Header version: %d, req. %d, sector %d" ", mk_offset %" PRIu64 ", hidden_size %" PRIu64 - ", volume size %" PRIu64, (int)hdr->d.version, - (int)hdr->d.version_tc, (int)hdr->d.sector_size, + ", volume size %" PRIu64, tcrypt_kdf[i].veracrypt ? + VCRYPT_HDR_MAGIC : TCRYPT_HDR_MAGIC, + (int)hdr->d.version, (int)hdr->d.version_tc, (int)hdr->d.sector_size, hdr->d.mk_offset, hdr->d.hidden_volume_size, hdr->d.volume_size); log_dbg("TCRYPT: Header cipher %s-%s, key size %zu", params->cipher, params->mode, params->key_size); @@ -1026,11 +1042,13 @@ int TCRYPT_dump(struct crypt_device *cd, struct tcrypt_phdr *hdr, struct crypt_params_tcrypt *params) { - log_std(cd, "TCRYPT header information for %s\n", + log_std(cd, "%s header information for %s\n", + hdr->d.magic[0] == 'T' ? "TCRYPT" : "VERACRYPT", device_path(crypt_metadata_device(cd))); if (hdr->d.version) { log_std(cd, "Version: \t%d\n", hdr->d.version); - log_std(cd, "Driver req.:\t%d\n", hdr->d.version_tc); + log_std(cd, "Driver req.:\t%x.%x\n", hdr->d.version_tc >> 8, + hdr->d.version_tc & 0xFF); log_std(cd, "Sector size:\t%" PRIu32 "\n", hdr->d.sector_size); log_std(cd, "MK offset:\t%" PRIu64 "\n", hdr->d.mk_offset); diff --git a/lib/tcrypt/tcrypt.h b/lib/tcrypt/tcrypt.h index 6328b58b..21ecba97 100644 --- a/lib/tcrypt/tcrypt.h +++ b/lib/tcrypt/tcrypt.h @@ -29,6 +29,7 @@ #define TCRYPT_HDR_LEN 448 #define TCRYPT_HDR_KEY_LEN 192 #define TCRYPT_HDR_MAGIC "TRUE" +#define VCRYPT_HDR_MAGIC "VERA" #define TCRYPT_HDR_MAGIC_LEN 4 #define TCRYPT_HDR_HIDDEN_OFFSET_OLD -1536 diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 index 95641b61..92e620c8 100644 --- a/man/cryptsetup.8 +++ b/man/cryptsetup.8 @@ -419,8 +419,9 @@ size). .PP See also section 7 of the FAQ and \fBhttp://loop-aes.sourceforge.net\fR for more information regarding loop-AES. -.SH TCRYPT (TrueCrypt-compatible) EXTENSION -cryptsetup supports mapping of TrueCrypt or tcplay encrypted partition +.SH TCRYPT (TrueCrypt-compatible and VeraCrypt) EXTENSION +cryptsetup supports mapping of TrueCrypt, tcplay or VeraCrypt +(with \fB\-\-veracrypt\fR option) encrypted partition using a native Linux kernel API. Header formatting and TCRYPT header change is not supported, cryptsetup never changes TCRYPT header on-device. @@ -438,6 +439,11 @@ 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. +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). + \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 8075eb15..8fc4d6c1 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -63,6 +63,7 @@ static int opt_test_passphrase = 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; @@ -288,7 +289,8 @@ static int action_open_tcrypt(void) 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; uint32_t activate_flags = 0; @@ -361,7 +363,8 @@ static int action_tcryptDump(void) 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), }; int r; @@ -1505,6 +1508,7 @@ int main(int argc, const char **argv) { "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 }, @@ -1609,6 +1613,8 @@ int main(int argc, const char **argv) } 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") || @@ -1724,6 +1730,11 @@ int main(int argc, const char **argv) _("Option --tcrypt-hidden cannot be combined with --allow-discards.\n"), poptGetInvocationName(popt_context)); + if (opt_veracrypt && strcmp(opt_type, "tcrypt")) + usage(popt_context, EXIT_FAILURE, + _("Option --veracrypt is supported only for TCRYPT device type.\n"), + poptGetInvocationName(popt_context)); + if (opt_debug) { opt_verbose = 1; crypt_set_debug_level(-1); diff --git a/tests/tcrypt-compat-test b/tests/tcrypt-compat-test index 8214e8e4..efb0e06e 100755 --- a/tests/tcrypt-compat-test +++ b/tests/tcrypt-compat-test @@ -70,23 +70,23 @@ export LANG=C [ ! -d $TST_DIR ] && tar xjf tcrypt-images.tar.bz2 echo "HEADER CHECK" -for file in $(ls $TST_DIR/tc_*) ; do +for file in $(ls $TST_DIR/[tv]c_*) ; do echo -n " $file" - echo $PASSWORD | $CRYPTSETUP tcryptDump $file >/dev/null || fail + echo $PASSWORD | $CRYPTSETUP tcryptDump --veracrypt $file >/dev/null || fail echo " [OK]" done echo "HEADER CHECK (HIDDEN)" -for file in $(ls $TST_DIR/tc_*-hidden) ; do +for file in $(ls $TST_DIR/[tv]c_*-hidden) ; do echo -n " $file (hidden)" - echo $PASSWORD_HIDDEN | $CRYPTSETUP tcryptDump --tcrypt-hidden $file >/dev/null || fail + echo $PASSWORD_HIDDEN | $CRYPTSETUP tcryptDump --tcrypt-hidden --veracrypt $file >/dev/null || fail echo " [OK]" done echo "HEADER KEYFILES CHECK" -for file in $(ls $TST_DIR/tck_*) ; do +for file in $(ls $TST_DIR/[tv]ck_*) ; do echo -n " $file" - echo $PASSWORD | $CRYPTSETUP tcryptDump -d $TST_DIR/keyfile1 -d $TST_DIR/keyfile2 $file >/dev/null || fail + echo $PASSWORD | $CRYPTSETUP tcryptDump --veracrypt -d $TST_DIR/keyfile1 -d $TST_DIR/keyfile2 $file >/dev/null || fail echo " [OK]" done @@ -97,9 +97,9 @@ if [ $(id -u) != 0 ]; then fi echo "ACTIVATION FS UUID CHECK" -for file in $(ls $TST_DIR/tc_*) ; do +for file in $(ls $TST_DIR/[tv]c_*) ; do echo -n " $file" - out=$(echo $PASSWORD | $CRYPTSETUP tcryptOpen -r $file $MAP 2>&1) + out=$(echo $PASSWORD | $CRYPTSETUP tcryptOpen --veracrypt -r $file $MAP 2>&1) ret=$? [ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT legacy mode" ) && echo " [N/A]" && continue [ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT compatible mapping" ) && echo " [N/A]" && continue @@ -113,9 +113,9 @@ for file in $(ls $TST_DIR/tc_*) ; do done echo "ACTIVATION FS UUID (HIDDEN) CHECK" -for file in $(ls $TST_DIR/tc_*-hidden) ; do +for file in $(ls $TST_DIR/[tv]c_*-hidden) ; do echo -n " $file" - out=$(echo $PASSWORD_HIDDEN | $CRYPTSETUP tcryptOpen -r $file $MAP --tcrypt-hidden 2>&1) + out=$(echo $PASSWORD_HIDDEN | $CRYPTSETUP tcryptOpen --veracrypt -r $file $MAP --tcrypt-hidden 2>&1) ret=$? [ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT legacy mode" ) && echo " [N/A]" && continue [ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT compatible mapping" ) && echo " [N/A]" && continue diff --git a/tests/tcrypt-images.tar.bz2 b/tests/tcrypt-images.tar.bz2 index 02db4ae8..4ca5473b 100644 Binary files a/tests/tcrypt-images.tar.bz2 and b/tests/tcrypt-images.tar.bz2 differ