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 */
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;
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);
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);
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;
}
#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)
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,
#define MAX_CIPHER_LEN 32
#define MAX_CIPHER_LEN_STR "32"
+#define MAX_KEYFILES 32
struct crypt_device;
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;
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;
/* TCRYPT header is encrypted, get passphrase now */
r = crypt_get_key(_("Enter passphrase: "),
CONST_CAST(char**)¶ms.passphrase,
- ¶ms.passphrase_size,
- opt_keyfile_offset, opt_keyfile_size,
- NULL, opt_timeout,
- _verify_passphrase(0),
- cd);
+ ¶ms.passphrase_size, 0, 0, NULL, opt_timeout,
+ _verify_passphrase(0), cd);
if (r < 0)
goto out;
{ "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") },
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 ||