From: Milan Broz Date: Fri, 16 Nov 2012 13:57:05 +0000 (+0100) Subject: TCRYPT: support keyfiles X-Git-Tag: upstream/1.6~158 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Fcryptsetup.git;a=commitdiff_plain;h=ecf993834cfdfc3ff9e3584845ffce9a5b967184 TCRYPT: support keyfiles --- diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 747cb0c..b1f5f0c 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -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 */ diff --git a/lib/setup.c b/lib/setup.c index 29c1f0f..38ec6d5 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -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; diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index 31b0916..6ccd148 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -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; } diff --git a/lib/tcrypt/tcrypt.h b/lib/tcrypt/tcrypt.h index 577221e..e05e468 100644 --- a/lib/tcrypt/tcrypt.h +++ b/lib/tcrypt/tcrypt.h @@ -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, diff --git a/lib/utils_crypt.h b/lib/utils_crypt.h index 692264f..9bf8ab4 100644 --- a/lib/utils_crypt.h +++ b/lib/utils_crypt.h @@ -26,6 +26,7 @@ #define MAX_CIPHER_LEN 32 #define MAX_CIPHER_LEN_STR "32" +#define MAX_KEYFILES 32 struct crypt_device; diff --git a/src/cryptsetup.c b/src/cryptsetup.c index b520d40..5387915 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -24,7 +24,11 @@ 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**)¶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; @@ -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 ||