TCRYPT: support keyfiles
authorMilan Broz <gmazyland@gmail.com>
Fri, 16 Nov 2012 13:57:05 +0000 (14:57 +0100)
committerMilan Broz <gmazyland@gmail.com>
Mon, 19 Nov 2012 20:25:26 +0000 (21:25 +0100)
lib/libcryptsetup.h
lib/setup.c
lib/tcrypt/tcrypt.c
lib/tcrypt/tcrypt.h
lib/utils_crypt.h
src/cryptsetup.c

index 747cb0c..b1f5f0c 100644 (file)
@@ -395,6 +395,8 @@ struct crypt_params_verity {
 struct crypt_params_tcrypt {
        const char *passphrase;
        size_t passphrase_size;
+       const char **keyfiles;
+       unsigned int keyfiles_count;
        const char *hash_name;     /**< hash function for PBKDF */
        const char *cipher[3];     /**< cipher chain */
        const char *mode;          /**< cipher block mode */
index 29c1f0f..38ec6d5 100644 (file)
@@ -634,9 +634,15 @@ static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcryp
        if (r < 0)
                return r;
 
-       r = TCRYPT_read_phdr(cd, &cd->tcrypt_hdr, &cd->tcrypt_params,
-                            params->passphrase, params->passphrase_size,
-                            params->flags);
+       memcpy(&cd->tcrypt_params, params, sizeof(*params));
+
+       r = TCRYPT_read_phdr(cd, &cd->tcrypt_hdr, &cd->tcrypt_params);
+
+       cd->tcrypt_params.passphrase = NULL;
+       cd->tcrypt_params.passphrase_size = 0;
+       cd->tcrypt_params.keyfiles = NULL;
+       cd->tcrypt_params.keyfiles_count = 0;
+
        if (r < 0)
                return r;
 
index 31b0916..6ccd148 100644 (file)
@@ -248,24 +248,80 @@ static int decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
        return r;
 }
 
+static int pool_keyfile(struct crypt_device *cd,
+                       unsigned char pool[TCRYPT_KEY_POOL_LEN],
+                       const char *keyfile)
+{
+       unsigned char data[TCRYPT_KEYFILE_LEN];
+       int i, j, fd, data_size;
+       uint32_t crc;
+       unsigned char *crc_c = (unsigned char*)&crc;
+
+       log_dbg("TCRYPT: using keyfile %s.", keyfile);
+
+       fd = open(keyfile, O_RDONLY);
+       if (fd < 0) {
+               log_err(cd, _("Failed to open key file.\n"));
+               return -EIO;
+       }
+
+       /* FIXME: add while */
+       data_size = read(fd, data, TCRYPT_KEYFILE_LEN);
+       close(fd);
+       if (data_size < 0) {
+               log_err(cd, _("Error reading keyfile %s.\n"), keyfile);
+               return -EIO;
+       }
+
+       for (i = 0, j = 0, crc = ~0U; i < data_size; i++) {
+               crc = crypt_crc32(crc, &data[i], 1);
+               pool[j++] += crc_c[3];
+               pool[j++] += crc_c[2];
+               pool[j++] += crc_c[1];
+               pool[j++] += crc_c[0];
+               j %= TCRYPT_KEY_POOL_LEN;
+       }
+
+       crc = 0;
+       memset(data, 0, TCRYPT_KEYFILE_LEN);
+
+       return 0;
+}
+
 static int TCRYPT_init_hdr(struct crypt_device *cd,
                           struct tcrypt_phdr *hdr,
-                          struct crypt_params_tcrypt *params,
-                          const char *passphrase,
-                          size_t passphrase_size)
+                          struct crypt_params_tcrypt *params)
 {
+       unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {};
+       size_t passphrase_size;
        char *key;
        int r, i;
 
        if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN))
                return -ENOMEM;
 
+       if (params->keyfiles_count)
+               passphrase_size = TCRYPT_KEY_POOL_LEN;
+       else
+               passphrase_size = params->passphrase_size;
+
+       /* Calculate pool content from keyfiles */
+       for (i = 0; i < params->keyfiles_count; i++) {
+               r = pool_keyfile(cd, pwd, params->keyfiles[i]);
+               if (r < 0)
+                       goto out;
+       }
+
+       /* If provided password, combine it with pool */
+       for (i = 0; i < params->passphrase_size; i++)
+               pwd[i] += params->passphrase[i];
+
        for (i = 0; tcrypt_kdf[i].name; i++) {
                /* Derive header key */
                log_dbg("TCRYPT: trying KDF: %s-%s-%d.",
                        tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations);
                r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash,
-                               passphrase, passphrase_size,
+                               (char*)pwd, passphrase_size,
                                hdr->salt, TCRYPT_HDR_SALT_LEN,
                                key, TCRYPT_HDR_KEY_LEN,
                                tcrypt_kdf[i].iterations);
@@ -277,25 +333,26 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
                if (r != -EPERM)
                        break;
        }
-       free(key);
 
        if (r < 0)
-               return r;
+               goto out;
 
        r = hdr_from_disk(hdr, params, i, r);
        if (r < 0)
-               return r;
+               goto out;
 
        hdr_info(cd, hdr, params);
-       return 0;
+out:
+       memset(pwd, 0, TCRYPT_KEY_POOL_LEN);
+       if (key)
+               memset(key, 0, TCRYPT_HDR_KEY_LEN);
+       free(key);
+       return r;
 }
 
 int TCRYPT_read_phdr(struct crypt_device *cd,
                     struct tcrypt_phdr *hdr,
-                    struct crypt_params_tcrypt *params,
-                    const char *passphrase,
-                    size_t passphrase_size,
-                    uint32_t flags)
+                    struct crypt_params_tcrypt *params)
 {
        struct device *device = crypt_metadata_device(cd);
        ssize_t hdr_size = sizeof(struct tcrypt_phdr);
@@ -312,19 +369,18 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
                return -EINVAL;
        }
 
-       if ((flags & CRYPT_TCRYPT_HIDDEN_HEADER) &&
+       if ((params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) &&
            lseek(devfd, TCRYPT_HDR_HIDDEN_OFFSET, SEEK_SET) < 0) {
                log_err(cd, _("Cannot seek to hidden header for %s.\n"), device_path(device));
-               r = -EIO;
-               goto out;
+               close(devfd);
+               return -EIO;
        }
 
-       if (read_blockwise(devfd, device_block_size(device), hdr, hdr_size) == hdr_size) {
-               params->flags = flags;
-               r = TCRYPT_init_hdr(cd, hdr, params, passphrase, passphrase_size);
-       } else
+       if (read_blockwise(devfd, device_block_size(device), hdr, hdr_size) == hdr_size)
+               r = TCRYPT_init_hdr(cd, hdr, params);
+       else
                r = -EIO;
-out:
+
        close(devfd);
        return r;
 }
index 577221e..e05e468 100644 (file)
@@ -33,6 +33,8 @@
 #define TCRYPT_HDR_HIDDEN_OFFSET 65536
 
 #define TCRYPT_LRW_IKEY_LEN 16
+#define TCRYPT_KEY_POOL_LEN 64
+#define TCRYPT_KEYFILE_LEN  1048576
 
 #define TCRYPT_HDR_FLAG_SYSTEM    (1 << 0)
 #define TCRYPT_HDR_FLAG_NONSYSTEM (1 << 1)
@@ -64,10 +66,7 @@ struct tcrypt_phdr {
 
 int TCRYPT_read_phdr(struct crypt_device *cd,
                     struct tcrypt_phdr *hdr,
-                    struct crypt_params_tcrypt *params,
-                    const char *passphrase,
-                    size_t passphrase_size,
-                    uint32_t flags);
+                    struct crypt_params_tcrypt *params);
 
 int TCRYPT_activate(struct crypt_device *cd,
                     const char *name,
index 692264f..9bf8ab4 100644 (file)
@@ -26,6 +26,7 @@
 
 #define MAX_CIPHER_LEN         32
 #define MAX_CIPHER_LEN_STR     "32"
+#define MAX_KEYFILES           32
 
 struct crypt_device;
 
index b520d40..5387915 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;
@@ -258,7 +262,10 @@ out:
 static int action_tcryptOpen(int arg __attribute__((unused)))
 {
        struct crypt_device *cd = NULL;
-       struct crypt_params_tcrypt params = {};
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+       };
        const char *activated_name;
        uint32_t flags = 0;
        int r;
@@ -271,11 +278,8 @@ static int action_tcryptOpen(int arg __attribute__((unused)))
        /* TCRYPT header is encrypted, get passphrase now */
        r = crypt_get_key(_("Enter passphrase: "),
                          CONST_CAST(char**)&params.passphrase,
-                         &params.passphrase_size,
-                         opt_keyfile_offset, opt_keyfile_size,
-                         NULL, opt_timeout,
-                         _verify_passphrase(0),
-                         cd);
+                         &params.passphrase_size, 0, 0, NULL, opt_timeout,
+                         _verify_passphrase(0), cd);
        if (r < 0)
                goto out;
 
@@ -1216,7 +1220,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") },
@@ -1266,6 +1270,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 ||