[systemd-devel] [PATCH 3/3] cryptsetup: Add tcrypt support

Jan Janssen medhefgo at web.de
Tue Jul 2 06:26:27 PDT 2013


Tcrypt uses a different approach to passphrases/key files. The
passphrase and all key files are incorpaorated into the "password"
to open the volume. So, the idea of slots that provide a way to
open the volume with different passphrases/key files that are
independent from each other like with LUKS does not apply.

Therefore, we use the key file from /etc/crypttab as the source
for the passphrase. If the passphrase of a volume is empty, using
/dev/null as key file is enough.

The actual key files that are combined with the passphrase into
a password are provided as a new option in /etc/crypttab and can
be given multiple times if more than one key file was used for a
volume.
---
 man/crypttab.xml            | 300 +++++++++++++++++++++++++++-----------------
 src/cryptsetup/cryptsetup.c |  81 +++++++++++-
 2 files changed, 259 insertions(+), 122 deletions(-)

diff --git a/man/crypttab.xml b/man/crypttab.xml
index 1063b46..386fa0d 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -75,23 +75,29 @@
                 fields are mandatory, the remaining two are
                 optional.</para>
 
+                <para>Setting up encrypted block devices using this file
+                supports three encryption modes: LUKS, TrueCrypt and plain.
+                See <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                for more information about each mode. When no mode is specified
+                in the options field and the block device contains a LUKS
+                signature, it is opened as a LUKS device; otherwise it is
+                assumed to be in raw dm-crypt (plain mode) format.</para>
+
                 <para>The first field contains the name of the
                 resulting encrypted block device; the device is set up
                 within <filename>/dev/mapper/</filename>.</para>
 
                 <para>The second field contains a path to the
-                underlying block device, or a specification of a block
+                underlying block device or file, or a specification of a block
                 device via <literal>UUID=</literal> followed by the
-                UUID.  If the block device contains a LUKS signature,
-                it is opened as a LUKS encrypted partition; otherwise
-                it is assumed to be a raw dm-crypt partition.</para>
+                UUID.</para>
 
                 <para>The third field specifies the encryption
                 password.  If the field is not present or the password
-                is set to none, the password has to be manually
-                entered during system boot.  Otherwise the field is
-                interpreted as a path to a file containing the
-                encryption password.  For swap encryption
+                is set to none or <literal>-</literal>, the password has
+                to be manually entered during system boot.  Otherwise the
+                field is interpreted as a absolute path to a file containing the
+                encryption password. For swap encryption
                 <filename>/dev/urandom</filename> or the hardware
                 device <filename>/dev/hw_random</filename> can be used
                 as the password file; using
@@ -104,181 +110,237 @@
                 options are recognized:</para>
 
                 <variablelist class='crypttab-options'>
+
+                        <varlistentry>
+                                <term><varname>allow-discards</varname></term>
+
+                                <listitem><para>Allow discard requests to be
+                                passed through the encrypted block device. This
+                                improves performance on SSD storage but has
+                                security implications.</para></listitem>
+                        </varlistentry>
+
                         <varlistentry>
                                 <term><varname>cipher=</varname></term>
 
-                                <listitem><para>Specifies the cipher
-                                to use; see
+                                <listitem><para>Specifies the cipher to use. See
                                 <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-                                for possible values and the default
-                                value of this option.  A cipher with
-                                unpredictable IV values, such as
-                                <literal>aes-cbc-essiv:sha256</literal>,
-                                is recommended. </para></listitem>
+                                for possible values and the default value of
+                                this option. A cipher with unpredictable IV
+                                values, such as <literal>aes-cbc-essiv:sha256</literal>,
+                                is recommended.</para></listitem>
                         </varlistentry>
 
-
                         <varlistentry>
-                                <term><varname>size=</varname></term>
+                                <term><varname>hash=</varname></term>
 
-                                <listitem><para>Specifies the key size
-                                in bits; see
+                                <listitem><para>Specifies the hash to use for
+                                password hashing. See
                                 <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-                                for possible values and the default
-                                value of this
-                                option. </para></listitem>
+                                for possible values and the default value of
+                                this option.</para></listitem>
                         </varlistentry>
 
+                        <varlistentry>
+                                <term><varname>keyfile-offset=</varname></term>
+
+                                <listitem><para>Specifies the number of bytes to
+                                skip at the start of the key file. See
+                                <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                                for possible values and the default value of
+                                this option.</para></listitem>
+                        </varlistentry>
 
                         <varlistentry>
                                 <term><varname>keyfile-size=</varname></term>
 
                                 <listitem><para>Specifies the maximum number
-                                of bytes to read from the keyfile; see
+                                of bytes to read from the key file. See
                                 <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-                                for possible values and the default
-                                value of this option. This option is ignored
-                                in plain encryption mode, as the keyfile-size is then given by the key size.</para></listitem>
+                                for possible values and the default value of
+                                this option. This option is ignored in plain
+                                encryption mode, as the key file size is then
+                                given by the key size.</para></listitem>
                         </varlistentry>
 
-
                         <varlistentry>
-                                <term><varname>keyfile-offset=</varname></term>
+                                <term><varname>luks</varname></term>
 
-                                <listitem><para>Specifies the number
-                                of bytes to skip at the start of
-                                the keyfile; see
-                                <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-                                for possible values and the default
-                                value of this option.</para></listitem>
+                                <listitem><para>Force LUKS mode. When this mode
+                                is used the following options are ignored since
+                                they are provided by the LUKS header on the
+                                device: <varname>cipher=</varname>,
+                                <varname>hash=</varname>,
+                                <varname>size=</varname>.</para></listitem>
                         </varlistentry>
 
-
                         <varlistentry>
-                                <term><varname>hash=</varname></term>
+                                <term><varname>noauto</varname></term>
 
-                                <listitem><para>Specifies the hash to
-                                use for password hashing; see
-                                <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry> for possible values and
-                                the default value of this
-                                option. </para></listitem>
+                                <listitem><para>This device will not be
+                                automatically unlocked on boot.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>tries=</varname></term>
+                                <term><varname>nofail</varname></term>
 
-                                <listitem><para>Specifies the maximum
-                                number of times the user is queried
-                                for a password.</para></listitem>
+                                <listitem><para>The system will not wait for the
+                                device to show up and be unlocked at boot, and
+                                not fail the boot if it doesn't show up.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>verify</varname></term>
+                                <term><varname>plain</varname></term>
 
-                                <listitem><para> If the encryption
-                                password is read from console, it has
-                                to be entered twice (to prevent
-                                typos). </para></listitem>
+                                <listitem><para>Force plain encryption mode.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
                                 <term><varname>read-only</varname></term><term><varname>readonly</varname></term>
 
-                                <listitem><para>Set up the encrypted
-                                block device in read-only
-                                mode.</para></listitem>
+                                <listitem><para>Set up the encrypted block
+                                device in read-only mode.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>allow-discards</varname></term>
+                                <term><varname>size=</varname></term>
 
-                                <listitem><para>Allow discard requests
-                                to be passed through the encrypted
-                                block device. This improves
-                                performance on SSD storage but has
-                                security
-                                implications.</para></listitem>
+                                <listitem><para>Specifies the key size
+                                in bits. See
+                                <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                                for possible values and the default value of
+                                this option.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>luks</varname></term>
+                                <term><varname>swap</varname></term>
 
-                                <listitem><para>Force LUKS mode.</para></listitem>
+                                <listitem><para>The encrypted block device will
+                                be used as a swap device, and will be formatted
+                                accordingly after setting up the encrypted
+                                block device, with
+                                <citerefentry><refentrytitle>mkswap</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+                                This option implies <varname>plain</varname>.</para>
+
+                                <para>WARNING: Using the <varname>swap</varname>
+                                option will destroy the contents of the named
+                                partition during every boot, so make sure the
+                                underlying block device is specified correctly.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>plain</varname></term>
+                                <term><varname>tcrypt</varname></term>
+
+                                <listitem><para>Use TrueCrypt encryption mode.
+                                When this mode is used the following options are
+                                ignored since they are provided by the TrueCrypt
+                                header on the device or don't apply:
+                                <varname>cipher=</varname>,
+                                <varname>hash=</varname>,
+                                <varname>keyfile-offset=</varname>,
+                                <varname>keyfile-size=</varname>,
+                                <varname>size=</varname>.</para>
+
+                                <para>When this mode is used, the passphrase is
+                                read from the key file given in the third field.
+                                Only the first line of this file is read,
+                                excluding the new line character.</para>
+
+                                <para>Note that the TrueCrypt format uses both
+                                passphrase and key files to derive a password
+                                for the volume. Therefore, the passphrases and
+                                all key files need to be provided. Use
+                                <varname>tcrypt-keyfile=</varname> to provide
+                                the absolute path to all key files. When using
+                                an empty passphrase in combination with one or
+                                more key files, use <literal>/dev/null</literal>
+                                as the password file in the third field.</para></listitem>
+                        </varlistentry>
 
-                                <listitem><para>Force plain encryption
-                                mode.</para></listitem>
+                        <varlistentry>
+                                <term><varname>tcrypt-hidden</varname></term>
+
+                                <listitem><para>Use the hidden TrueCrypt volume.
+                                This implies <varname>tcrypt</varname>.</para>
+
+                                <para>This will map the hidden volume that is
+                                inside of the volume provided in the second
+                                field. Please note that there is no protection
+                                for the hidden volume if the outer volume is
+                                mounted instead. See
+                                <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                                for more information on this limitation.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>timeout=</varname></term>
+                                <term><varname>tcrypt-keyfile=</varname></term>
+
+                                <listitem><para>Specifies the absolute path to a
+                                key file to use for a TrueCrypt volume. This
+                                implies <varname>tcrypt</varname> and can be
+                                used more than once to provide several key
+                                files.</para>
 
-                                <listitem><para>Specify the timeout
-                                for querying for a password. If no
-                                unit is specified seconds is used.
-                                Supported units are s, ms, us, min, h,
-                                d. A timeout of 0 waits indefinitely
-                                (which is the
-                                default).</para></listitem>
+                                <para>See the entry for <varname>tcrypt</varname>
+                                on the behavior of key files and passphrases
+                                when using TrueCrypt encryption mode.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>noauto</varname></term>
+                                <term><varname>tcrypt-system</varname></term>
+
+                                <listitem><para>Use TrueCrypt in system
+                                encryption mode. This implies
+                                <varname>tcrypt</varname>.</para>
+
+                                <para>Please note that when using this mode, the
+                                whole device needs to be given in the second
+                                field instead of the partition. For example: if
+                                <literal>/dev/sda2</literal> is the system
+                                encrypted TrueCrypt patition, <literal>/dev/sda</literal>
+                                has to be given.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><varname>timeout=</varname></term>
 
-                                <listitem><para> This device will not
-                                be automatically unlocked on
-                                boot. </para></listitem>
+                                <listitem><para>Specifies the timeout for
+                                querying for a password. If no unit is
+                                specified, seconds is used. Supported units are
+                                s, ms, us, min, h, d. A timeout of 0 waits
+                                indefinitely (which is the default).</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>nofail</varname></term>
+                                <term><varname>tmp</varname></term>
+
+                                <listitem><para>The encrypted block device will
+                                be prepared for using it as <filename>/tmp</filename>;
+                                it will be formatted using
+                                <citerefentry><refentrytitle>mke2fs</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+                                This option implies <varname>plain</varname>.</para>
 
-                                <listitem><para>The system will not
-                                wait for the device to show up and be
-                                unlocked at boot, and not fail the
-                                boot if it doesn't show
-                                up.</para></listitem>
+                                <para>WARNING: Using the <varname>tmp</varname>
+                                option will destroy the contents of the named
+                                partition during every boot, so make sure the
+                                underlying block device is specified correctly.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>swap</varname></term>
+                                <term><varname>tries=</varname></term>
 
-                                <listitem><para> The encrypted block
-                                device will be used as a swap
-                                partition, and will be formatted as a
-                                swap partition after setting up the
-                                encrypted block device, with
-                                <citerefentry><refentrytitle>mkswap</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
-
-                                <para>WARNING: Using the
-                                <varname>swap</varname> option will
-                                destroy the contents of the named
-                                partition during every boot, so make
-                                sure the underlying block device is
-                                specified
-                                correctly. </para></listitem>
+                                <listitem><para>Specifies the maximum number of
+                                times the user is queried for a password.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>tmp</varname></term>
+                                <term><varname>verify</varname></term>
 
-                                <listitem><para>The encrypted block
-                                device will be prepared for using it
-                                as <filename>/tmp</filename>
-                                partition: it will be formatted using
-                                <citerefentry><refentrytitle>mke2fs</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
-
-                                <para>WARNING: Using the
-                                <varname>tmp</varname> option will
-                                destroy the contents of the named
-                                partition during every boot, so make
-                                sure the underlying block device is
-                                specified
-                                correctly. </para></listitem>
+                                <listitem><para> If the encryption password is
+                                read from console, it has to be entered twice to
+                                prevent typos.</para></listitem>
                         </varlistentry>
+
                 </variablelist>
 
                 <para>At early boot and when the system manager
@@ -291,12 +353,14 @@
                 <title>Example</title>
                 <example>
                         <title>/etc/crypttab example</title>
-                        <para>Set up two encrypted block devices with
-                        LUKS: one normal one for storage, and another
-                        one for usage as swap device.</para>
-
-                        <programlisting>luks-2505567a-9e27-4efe-a4d5-15ad146c258b UUID=2505567a-9e27-4efe-a4d5-15ad146c258b - timeout=0
-swap /dev/sda7 /dev/urandom swap</programlisting>
+                        <para>Set up four encrypted block devices. One using
+                        LUKS for normal storage, another one for usage as a swap
+                        device and two TrueCrypt volumes.</para>
+
+                        <programlisting>luks       UUID=2505567a-9e27-4efe-a4d5-15ad146c258b
+swap       /dev/sda7       /dev/urandom             swap
+truecrypt  /dev/sda2       /etc/container_password  tcrypt
+hidden     /mnt/tc_hidden  /null                    tcrypt-hidden,tcrypt-keyfile=/etc/keyfile</programlisting>
                 </example>
         </refsect1>
 
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index cb48009..168936d 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -27,6 +27,7 @@
 #include <libcryptsetup.h>
 #include <libudev.h>
 
+#include "fileio.h"
 #include "log.h"
 #include "util.h"
 #include "path-util.h"
@@ -34,7 +35,7 @@
 #include "ask-password-api.h"
 #include "def.h"
 
-static const char *opt_type = NULL; /* LUKS1 or PLAIN */
+static const char *opt_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
 static char *opt_cipher = NULL;
 static unsigned opt_key_size = 0;
 static unsigned opt_keyfile_size = 0;
@@ -44,6 +45,9 @@ static unsigned opt_tries = 0;
 static bool opt_readonly = false;
 static bool opt_verify = false;
 static bool opt_discards = false;
+static bool opt_tcrypt_hidden = false;
+static bool opt_tcrypt_system = false;
+static char **opt_tcrypt_keyfiles = NULL;
 static usec_t opt_timeout = 0;
 
 /* Options Debian's crypttab knows we don't:
@@ -82,6 +86,14 @@ static int parse_one_option(const char *option) {
                         return 0;
                 }
 
+        } else if (startswith(option, "tcrypt-keyfile=")) {
+
+                opt_type = CRYPT_TCRYPT;
+                if (path_is_absolute(option+15))
+                        opt_tcrypt_keyfiles = strv_append(opt_tcrypt_keyfiles, strdup(option+15));
+                else
+                        log_error("Key file path '%s' is not absolute. Ignoring.", option+15);
+
         } else if (startswith(option, "keyfile-size=")) {
 
                 if (safe_atou(option+13, &opt_keyfile_size) < 0) {
@@ -121,7 +133,15 @@ static int parse_one_option(const char *option) {
                 opt_discards = true;
         else if (streq(option, "luks"))
                 opt_type = CRYPT_LUKS1;
-        else if (streq(option, "plain") ||
+        else if (streq(option, "tcrypt"))
+                opt_type = CRYPT_TCRYPT;
+        else if (streq(option, "tcrypt-hidden")) {
+                opt_type = CRYPT_TCRYPT;
+                opt_tcrypt_hidden = true;
+        } else if (streq(option, "tcrypt-system")) {
+                opt_type = CRYPT_TCRYPT;
+                opt_tcrypt_system = true;
+        } else if (streq(option, "plain") ||
                  streq(option, "swap") ||
                  streq(option, "tmp"))
                 opt_type = CRYPT_PLAIN;
@@ -301,6 +321,55 @@ static int get_password(const char *name, usec_t until, bool accept_cached, char
         return 0;
 }
 
+static int attach_tcrypt(struct crypt_device *cd,
+                                const char *name,
+                                const char **key_file,
+                                char **passwords,
+                                uint32_t flags) {
+        int r = 0;
+        _cleanup_free_ char *passphrase = NULL;
+        struct crypt_params_tcrypt params = {
+                .flags = CRYPT_TCRYPT_LEGACY_MODES,
+                .keyfiles = (const char **)opt_tcrypt_keyfiles,
+                .keyfiles_count = strv_length(opt_tcrypt_keyfiles)
+        };
+
+        assert(cd);
+        assert(name);
+        assert(key_file);
+
+        if (opt_tcrypt_hidden)
+                params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+        if (opt_tcrypt_system)
+                params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
+
+        if (*key_file) {
+                r = read_one_line_file(*key_file, &passphrase);
+                if (r < 0) {
+                        log_error("Failed to read key file: %s", strerror(-r));
+                        *key_file = NULL;
+                        return -EAGAIN;
+                }
+
+                params.passphrase = passphrase;
+        } else
+                params.passphrase = passwords[0];
+        params.passphrase_size = strlen(params.passphrase);
+
+        r = crypt_load(cd, CRYPT_TCRYPT, &params);
+        if (r < 0) {
+                if (*key_file && r == -EPERM) {
+                        log_error("Failed to activate using password file '%s'.", *key_file);
+                        *key_file = NULL;
+                        return -EAGAIN;
+                }
+                return r;
+        }
+
+        return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);;
+}
+
 static int attach_luks_or_plain(struct crypt_device *cd,
                                 const char *name,
                                 const char **key_file,
@@ -456,7 +525,7 @@ int main(int argc, char *argv[]) {
                     !streq(argv[4], "none")) {
 
                         if (!path_is_absolute(argv[4]))
-                                log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
+                                log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
                         else
                                 key_file = argv[4];
                 }
@@ -540,7 +609,10 @@ int main(int argc, char *argv[]) {
                                         goto finish;
                         }
 
-                        k = attach_luks_or_plain(cd, argv[2], &key_file, passwords, flags);
+                        if (streq_ptr(opt_type, CRYPT_TCRYPT))
+                                k = attach_tcrypt(cd, argv[2], &key_file, passwords, flags);
+                        else
+                                k = attach_luks_or_plain(cd, argv[2], &key_file, passwords, flags);
                         if (k >= 0)
                                 break;
                         else if (k == -EAGAIN)
@@ -590,6 +662,7 @@ finish:
 
         free(opt_cipher);
         free(opt_hash);
+        strv_free(opt_tcrypt_keyfiles);
 
         return r;
 }
-- 
1.8.3.2



More information about the systemd-devel mailing list