Exemple #1
0
// FIXME: move this to tools and handle EINTR
static int _read_mk(const char *file, char **key, int keysize)
{
	int fd;

	if (keysize <= 0 || keysize > MAX_KEY_SIZE) {
		log_err(_("Invalid key size."));
		return -EINVAL;
	}

	*key = crypt_safe_alloc(keysize);
	if (!*key)
		return -ENOMEM;

	fd = open(file, O_RDONLY);
	if (fd == -1) {
		log_err(_("Cannot read keyfile %s."), file);
		goto fail;
	}
	if ((read(fd, *key, keysize) != keysize)) {
		log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
		close(fd);
		goto fail;
	}
	close(fd);
	return 0;
fail:
	crypt_safe_free(*key);
	*key = NULL;
	return -EINVAL;
}
Exemple #2
0
/* Try to open a particular key slot */
static int LUKS_open_key(unsigned int keyIndex,
		  const char *password,
		  size_t passwordLen,
		  struct luks_phdr *hdr,
		  struct volume_key *vk,
		  struct crypt_device *ctx)
{
	crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
	struct volume_key *derived_key;
	char *AfKey;
	size_t AFEKSize;
	int r;

	log_dbg("Trying to open key slot %d [%s].", keyIndex,
		dbg_slot_state(ki));

	if (ki < CRYPT_SLOT_ACTIVE)
		return -ENOENT;

	derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
	if (!derived_key)
		return -ENOMEM;

	assert(vk->keylength == hdr->keyBytes);
	AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
	AfKey = crypt_safe_alloc(AFEKSize);
	if (!AfKey) {
		r = -ENOMEM;
		goto out;
	}

	r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen,
			hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
			derived_key->key, hdr->keyBytes,
			hdr->keyblock[keyIndex].passwordIterations);
	if (r < 0)
		goto out;

	log_dbg("Reading key slot %d area.", keyIndex);
	r = LUKS_decrypt_from_storage(AfKey,
				      AFEKSize,
				      hdr->cipherName, hdr->cipherMode,
				      derived_key,
				      hdr->keyblock[keyIndex].keyMaterialOffset,
				      ctx);
	if (r < 0)
		goto out;

	r = AF_merge(AfKey,vk->key,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
	if (r < 0)
		goto out;

	r = LUKS_verify_volume_key(hdr, vk);
	if (!r)
		log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
out:
	crypt_safe_free(AfKey);
	crypt_free_volume_key(derived_key);
	return r;
}
Exemple #3
0
static int _read_keys(char **integrity_key, struct crypt_params_integrity *params)
{
	char *int_key = NULL, *journal_integrity_key = NULL, *journal_crypt_key = NULL;
	int r;

	if (integrity_key && opt_integrity_key_file) {
		r = _read_mk(opt_integrity_key_file, &int_key, opt_integrity_key_size);
		if (r < 0)
			return r;
		params->integrity_key_size = opt_integrity_key_size;
	}

	if (opt_journal_integrity_key_file) {
		r = _read_mk(opt_journal_integrity_key_file, &journal_integrity_key, opt_journal_integrity_key_size);
		if (r < 0) {
			crypt_safe_free(int_key);
			return r;
		}
		params->journal_integrity_key = journal_integrity_key;
		params->journal_integrity_key_size = opt_journal_integrity_key_size;
	}

	if (opt_journal_crypt_key_file) {
		r = _read_mk(opt_journal_crypt_key_file, &journal_crypt_key, opt_journal_crypt_key_size);
		if (r < 0) {
			crypt_safe_free(int_key);
			crypt_safe_free(journal_integrity_key);
			return r;
		}
		params->journal_crypt_key = journal_crypt_key;
		params->journal_crypt_key_size = opt_journal_crypt_key_size;
	}

	if (integrity_key)
		*integrity_key = int_key;

	return 0;
}
Exemple #4
0
int LUKS_set_key(unsigned int keyIndex,
		 const char *password, size_t passwordLen,
		 struct luks_phdr *hdr, struct volume_key *vk,
		 uint32_t iteration_time_ms,
		 uint64_t *PBKDF2_per_sec,
		 struct crypt_device *ctx)
{
	struct volume_key *derived_key;
	char *AfKey = NULL;
	size_t AFEKSize;
	uint64_t PBKDF2_temp;
	int r;

	if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
		log_err(ctx, _("Key slot %d active, purge first.\n"), keyIndex);
		return -EINVAL;
	}

	/* LUKS keyslot has always at least 4000 stripes accoding to specification */
	if(hdr->keyblock[keyIndex].stripes < 4000) {
	        log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?\n"),
			keyIndex);
	         return -EINVAL;
	}

	log_dbg("Calculating data for key slot %d", keyIndex);

	r = crypt_benchmark_kdf(ctx, "pbkdf2", hdr->hashSpec,
				"foo", 3, "bar", 3, PBKDF2_per_sec);
	if (r < 0) {
		log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
			hdr->hashSpec);
		return r;
	}

	/*
	 * Avoid floating point operation
	 * Final iteration count is at least LUKS_SLOT_ITERATIONS_MIN
	 */
	PBKDF2_temp = (*PBKDF2_per_sec / 2) * (uint64_t)iteration_time_ms;
	PBKDF2_temp /= 1024;
	if (PBKDF2_temp > UINT32_MAX)
		PBKDF2_temp = UINT32_MAX;
	hdr->keyblock[keyIndex].passwordIterations = at_least((uint32_t)PBKDF2_temp,
							      LUKS_SLOT_ITERATIONS_MIN);

	log_dbg("Key slot %d use %" PRIu32 " password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations);

	derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
	if (!derived_key)
		return -ENOMEM;

	r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
		       LUKS_SALTSIZE, CRYPT_RND_SALT);
	if (r < 0)
		goto out;

	r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen,
			hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
			derived_key->key, hdr->keyBytes,
			hdr->keyblock[keyIndex].passwordIterations);
	if (r < 0)
		goto out;

	/*
	 * AF splitting, the masterkey stored in vk->key is split to AfKey
	 */
	assert(vk->keylength == hdr->keyBytes);
	AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
	AfKey = crypt_safe_alloc(AFEKSize);
	if (!AfKey) {
		r = -ENOMEM;
		goto out;
	}

	log_dbg("Using hash %s for AF in key slot %d, %d stripes",
		hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes);
	r = AF_split(vk->key,AfKey,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
	if (r < 0)
		goto out;

	log_dbg("Updating key slot %d [0x%04x] area.", keyIndex,
		hdr->keyblock[keyIndex].keyMaterialOffset << 9);
	/* Encryption via dm */
	r = LUKS_encrypt_to_storage(AfKey,
				    AFEKSize,
				    hdr->cipherName, hdr->cipherMode,
				    derived_key,
				    hdr->keyblock[keyIndex].keyMaterialOffset,
				    ctx);
	if (r < 0)
		goto out;

	/* Mark the key as active in phdr */
	r = LUKS_keyslot_set(hdr, (int)keyIndex, 1);
	if (r < 0)
		goto out;

	r = LUKS_write_phdr(hdr, ctx);
	if (r < 0)
		goto out;

	r = 0;
out:
	crypt_safe_free(AfKey);
	crypt_free_volume_key(derived_key);
	return r;
}
Exemple #5
0
int LUKS_hdr_restore(
	const char *backup_file,
	struct luks_phdr *hdr,
	struct crypt_device *ctx)
{
	struct device *device = crypt_metadata_device(ctx);
	int r = 0, devfd = -1, diff_uuid = 0;
	ssize_t buffer_size = 0;
	char *buffer = NULL, msg[200];
	struct luks_phdr hdr_file;

	r = LUKS_read_phdr_backup(backup_file, &hdr_file, 0, ctx);
	if (r == -ENOENT)
		return r;

	if (!r)
		buffer_size = LUKS_device_sectors(hdr_file.keyBytes) << SECTOR_SHIFT;

	if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
		log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n"));
		r = -EINVAL;
		goto out;
	}

	buffer = crypt_safe_alloc(buffer_size);
	if (!buffer) {
		r = -ENOMEM;
		goto out;
	}

	devfd = open(backup_file, O_RDONLY);
	if (devfd == -1) {
		log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
		r = -EINVAL;
		goto out;
	}

	if (read(devfd, buffer, buffer_size) < buffer_size) {
		log_err(ctx, _("Cannot read header backup file %s.\n"), backup_file);
		r = -EIO;
		goto out;
	}
	close(devfd);

	r = LUKS_read_phdr(hdr, 0, 0, ctx);
	if (r == 0) {
		log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
		if(hdr->payloadOffset != hdr_file.payloadOffset ||
		   hdr->keyBytes != hdr_file.keyBytes) {
			log_err(ctx, _("Data offset or key size differs on device and backup, restore failed.\n"));
			r = -EINVAL;
			goto out;
		}
		if (memcmp(hdr->uuid, hdr_file.uuid, UUID_STRING_L))
			diff_uuid = 1;
	}

	if (snprintf(msg, sizeof(msg), _("Device %s %s%s"), device_path(device),
		 r ? _("does not contain LUKS header. Replacing header can destroy data on that device.") :
		     _("already contains LUKS header. Replacing header will destroy existing keyslots."),
		     diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "") < 0) {
		r = -ENOMEM;
		goto out;
	}

	if (!crypt_confirm(ctx, msg)) {
		r = -EINVAL;
		goto out;
	}

	log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes) to device %s.",
		sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device_path(device));

	devfd = device_open(device, O_RDWR);
	if (devfd == -1) {
		if (errno == EACCES)
			log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
				device_path(device));
		else
			log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
		r = -EINVAL;
		goto out;
	}

	if (write_blockwise(devfd, device_block_size(device), buffer, buffer_size) < buffer_size) {
		r = -EIO;
		goto out;
	}
	close(devfd);

	/* Be sure to reload new data */
	r = LUKS_read_phdr(hdr, 1, 0, ctx);
out:
	if (devfd != -1)
		close(devfd);
	crypt_safe_free(buffer);
	return r;
}
Exemple #6
0
int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
{
	struct device *device = crypt_metadata_device(ctx);
	struct luks_phdr hdr;
	int r = 0, devfd = -1;
	ssize_t hdr_size;
	ssize_t buffer_size;
	char *buffer = NULL;

	r = LUKS_read_phdr(&hdr, 1, 0, ctx);
	if (r)
		return r;

	hdr_size = LUKS_device_sectors(hdr.keyBytes) << SECTOR_SHIFT;
	buffer_size = size_round_up(hdr_size, crypt_getpagesize());

	buffer = crypt_safe_alloc(buffer_size);
	if (!buffer || hdr_size < LUKS_ALIGN_KEYSLOTS || hdr_size > buffer_size) {
		r = -ENOMEM;
		goto out;
	}

	log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes).",
		sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS);

	log_dbg("Output backup file size: %zu bytes.", buffer_size);

	devfd = device_open(device, O_RDONLY);
	if(devfd == -1) {
		log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device));
		r = -EINVAL;
		goto out;
	}

	if (read_blockwise(devfd, device_block_size(device), buffer, hdr_size) < hdr_size) {
		r = -EIO;
		goto out;
	}
	close(devfd);

	/* Wipe unused area, so backup cannot contain old signatures */
	if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS)
		memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr));

	devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
	if (devfd == -1) {
		if (errno == EEXIST)
			log_err(ctx, _("Requested header backup file %s already exists.\n"), backup_file);
		else
			log_err(ctx, _("Cannot create header backup file %s.\n"), backup_file);
		r = -EINVAL;
		goto out;
	}
	if (write(devfd, buffer, buffer_size) < buffer_size) {
		log_err(ctx, _("Cannot write header backup file %s.\n"), backup_file);
		r = -EIO;
		goto out;
	}
	close(devfd);

	r = 0;
out:
	if (devfd != -1)
		close(devfd);
	crypt_memzero(&hdr, sizeof(hdr));
	crypt_safe_free(buffer);
	return r;
}
int LUKS_set_key(unsigned int keyIndex,
		 const char *password, size_t passwordLen,
		 struct luks_phdr *hdr, struct volume_key *vk,
		 struct crypt_device *ctx)
{
	struct volume_key *derived_key;
	char *AfKey = NULL;
	size_t AFEKSize;
	struct crypt_pbkdf_type *pbkdf;
	int r;

	if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
		log_err(ctx, _("Key slot %d active, purge first."), keyIndex);
		return -EINVAL;
	}

	/* LUKS keyslot has always at least 4000 stripes according to specification */
	if(hdr->keyblock[keyIndex].stripes < 4000) {
	        log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?"),
			keyIndex);
	         return -EINVAL;
	}

	log_dbg("Calculating data for key slot %d", keyIndex);
	pbkdf = crypt_get_pbkdf(ctx);
	r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
	if (r < 0)
		return r;
	assert(pbkdf->iterations);

	/*
	 * Final iteration count is at least LUKS_SLOT_ITERATIONS_MIN
	 */
	hdr->keyblock[keyIndex].passwordIterations =
		at_least(pbkdf->iterations, LUKS_SLOT_ITERATIONS_MIN);
	log_dbg("Key slot %d use %" PRIu32 " password iterations.", keyIndex,
		hdr->keyblock[keyIndex].passwordIterations);

	derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
	if (!derived_key)
		return -ENOMEM;

	r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
		       LUKS_SALTSIZE, CRYPT_RND_SALT);
	if (r < 0)
		goto out;

	r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
			hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
			derived_key->key, hdr->keyBytes,
			hdr->keyblock[keyIndex].passwordIterations, 0, 0);
	if (r < 0)
		goto out;

	/*
	 * AF splitting, the masterkey stored in vk->key is split to AfKey
	 */
	assert(vk->keylength == hdr->keyBytes);
	AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
	AfKey = crypt_safe_alloc(AFEKSize);
	if (!AfKey) {
		r = -ENOMEM;
		goto out;
	}

	log_dbg("Using hash %s for AF in key slot %d, %d stripes",
		hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes);
	r = AF_split(vk->key,AfKey,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
	if (r < 0)
		goto out;

	log_dbg("Updating key slot %d [0x%04x] area.", keyIndex,
		hdr->keyblock[keyIndex].keyMaterialOffset << 9);
	/* Encryption via dm */
	r = LUKS_encrypt_to_storage(AfKey,
				    AFEKSize,
				    hdr->cipherName, hdr->cipherMode,
				    derived_key,
				    hdr->keyblock[keyIndex].keyMaterialOffset,
				    ctx);
	if (r < 0)
		goto out;

	/* Mark the key as active in phdr */
	r = LUKS_keyslot_set(hdr, (int)keyIndex, 1);
	if (r < 0)
		goto out;

	r = LUKS_write_phdr(hdr, ctx);
	if (r < 0)
		goto out;

	r = 0;
out:
	crypt_safe_free(AfKey);
	crypt_free_volume_key(derived_key);
	return r;
}
Exemple #8
0
static int action_format(int arg)
{
	struct crypt_device *cd = NULL;
	struct crypt_params_integrity params = {
		.journal_size = opt_journal_size,
		.interleave_sectors = opt_interleave_sectors,
		/* in bitmap mode we have to overload these values... */
		.journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark,
		.journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time,
		.buffer_sectors = opt_buffer_sectors,
		.tag_size = opt_tag_size,
		.sector_size = opt_sector_size ?: SECTOR_SIZE,
	};
	char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN];
	char *integrity_key = NULL, *msg = NULL;
	int r;
	size_t signatures;

	if (opt_integrity) {
		r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
		if (r < 0) {
			log_err(_("No known integrity specification pattern detected."));
			return r;
		}
		params.integrity = integrity;
	}

	if (opt_journal_integrity) {
		r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
		if (r < 0) {
			log_err(_("No known integrity specification pattern detected."));
			return r;
		}
		params.journal_integrity = journal_integrity;
	}

	if (opt_journal_crypt) {
		r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt);
		if (r < 0) {
			log_err(_("No known integrity specification pattern detected."));
			return r;
		}
		params.journal_crypt = journal_crypt;
	}

	r = _read_keys(&integrity_key, &params);
	if (r)
		goto out;

	r = crypt_init_data_device(&cd, action_argv[0], opt_data_device);
	if (r < 0)
		goto out;

	r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]);
	if (r == -1) {
		r = -ENOMEM;
		goto out;
	}

	r = yesDialog(msg, _("Operation aborted.\n")) ? 0 : -EINVAL;
	free(msg);
	if (r < 0)
		goto out;

	r = tools_detect_signatures(action_argv[0], 0, &signatures);
	if (r < 0)
		goto out;

	/* Signature candidates found */
	if (signatures && ((r =	tools_wipe_all_signatures(action_argv[0])) < 0))
		goto out;

	r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, &params);
	if (r < 0) /* FIXME: call wipe signatures again */
		goto out;

	if (!opt_batch_mode)
		log_std(_("Formatted with tag size %u, internal integrity %s.\n"), opt_tag_size, opt_integrity);

	if (!opt_no_wipe)
		r = _wipe_data_device(cd, integrity_key);
out:
	crypt_safe_free(integrity_key);
	crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key);
	crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key);
	crypt_free(cd);
	return r;
}

static int action_open(int arg)
{
	struct crypt_device *cd = NULL;
	struct crypt_params_integrity params = {
		/* in bitmap mode we have to overload these values... */
		.journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark,
		.journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time,
		.buffer_sectors = opt_buffer_sectors,
	};
	uint32_t activate_flags = 0;
	char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN];
	char *integrity_key = NULL;
	int r;

	if (opt_integrity) {
		r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
		if (r < 0) {
			log_err(_("No known integrity specification pattern detected."));
			return r;
		}
		params.integrity = integrity;
	}

	if (opt_journal_integrity) {
		r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
		if (r < 0) {
			log_err(_("No known integrity specification pattern detected."));
			return r;

		}
		params.journal_integrity = journal_integrity;
	}

	if (opt_journal_crypt) {
		r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt);
		if (r < 0) {
			log_err(_("No known integrity specification pattern detected."));
			return r;
		}
		params.journal_crypt = journal_crypt;
	}

	if (opt_integrity_nojournal || opt_integrity_bitmap)
		activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
	if (opt_integrity_recovery)
		activate_flags |= CRYPT_ACTIVATE_RECOVERY;
	if (opt_integrity_bitmap)
		activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;

	if (opt_integrity_recalculate)
		activate_flags |= CRYPT_ACTIVATE_RECALCULATE;

	r = _read_keys(&integrity_key, &params);
	if (r)
		goto out;

	if ((r = crypt_init_data_device(&cd, action_argv[0], opt_data_device)))
		goto out;

	r = crypt_load(cd, CRYPT_INTEGRITY, &params);
	if (r)
		goto out;

	r = crypt_activate_by_volume_key(cd, action_argv[1], integrity_key,
					 opt_integrity_key_size, activate_flags);
out:
	crypt_safe_free(integrity_key);
	crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key);
	crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key);
	crypt_free(cd);
	return r;
}

static int action_close(int arg)
{
	struct crypt_device *cd = NULL;
	int r;

	r = crypt_init_by_name(&cd, action_argv[0]);
	if (r == 0)
		r = crypt_deactivate(cd, action_argv[0]);

	crypt_free(cd);
	return r;
}

static int action_status(int arg)
{
	crypt_status_info ci;
	struct crypt_active_device cad;
	struct crypt_params_integrity ip = {};
	struct crypt_device *cd = NULL;
	char *backing_file;
	const char *device, *metadata_device;
	int path = 0, r = 0;

	/* perhaps a path, not a dm device name */
	if (strchr(action_argv[0], '/'))
		path = 1;

	ci = crypt_status(NULL, action_argv[0]);
	switch (ci) {
	case CRYPT_INVALID:
		r = -EINVAL;
		break;
	case CRYPT_INACTIVE:
		if (path)
			log_std("%s is inactive.\n", action_argv[0]);
		else
			log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
		r = -ENODEV;
		break;
	case CRYPT_ACTIVE:
	case CRYPT_BUSY:
		if (path)
			log_std("%s is active%s.\n", action_argv[0],
				ci == CRYPT_BUSY ? " and is in use" : "");
		else
			log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0],
				ci == CRYPT_BUSY ? " and is in use" : "");

		r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
		if (r < 0)
			goto out;

		log_std("  type:    %s\n", crypt_get_type(cd) ?: "n/a");

		r = crypt_get_active_device(cd, action_argv[0], &cad);
		if (r < 0)
			goto out;

		r = crypt_get_integrity_info(cd, &ip);
		if (r < 0)
			goto out;

		log_std("  tag size: %u\n", ip.tag_size);
		log_std("  integrity: %s\n", ip.integrity ?: "(none)");
		device = crypt_get_device_name(cd);
		metadata_device = crypt_get_metadata_device_name(cd);
		log_std("  device:  %s%s\n", device, metadata_device ? " (detached)" : "");
		if (crypt_loop_device(device)) {
			backing_file = crypt_loop_backing_file(device);
			log_std("  loop:    %s\n", backing_file);
			free(backing_file);
		}
		if (metadata_device) {
			log_std("  metadata device:  %s\n", metadata_device);
			if (crypt_loop_device(metadata_device)) {
				backing_file = crypt_loop_backing_file(metadata_device);
				log_std("  loop:    %s\n", backing_file);
				free(backing_file);
			}
		}
		log_std("  sector size:  %u bytes\n", crypt_get_sector_size(cd));
		log_std("  interleave sectors: %u\n", ip.interleave_sectors);
		log_std("  size:    %" PRIu64 " sectors\n", cad.size);
		log_std("  mode:    %s%s\n",
			cad.flags & CRYPT_ACTIVATE_READONLY ? "readonly" : "read/write",
			cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : "");
		log_std("  failures: %" PRIu64 "\n",
			crypt_get_active_integrity_failures(cd, action_argv[0]));
		if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) {
			log_std("  bitmap 512-byte sectors per bit: %u\n", ip.journal_watermark);
			log_std("  bitmap flush interval: %u ms\n", ip.journal_commit_time);
		} if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
			log_std("  journal: not active\n");
		} else {
			log_std("  journal size: %" PRIu64 " bytes\n", ip.journal_size);
			log_std("  journal watermark: %u%%\n", ip.journal_watermark);
			log_std("  journal commit time: %u ms\n", ip.journal_commit_time);
			if (ip.journal_integrity)
				log_std("  journal integrity MAC: %s\n", ip.journal_integrity);
			if (ip.journal_crypt)
				log_std("  journal encryption: %s\n", ip.journal_crypt);
		}
	}
out:
	crypt_free(cd);
	if (r == -ENOTSUP)
		r = 0;
	return r;
	return -EINVAL;
}

static int action_dump(int arg)
{
	struct crypt_device *cd = NULL;
	struct crypt_params_integrity params = {};
	int r;

	if ((r = crypt_init(&cd, action_argv[0])))
		return r;

	r = crypt_load(cd, CRYPT_INTEGRITY, &params);
	if (!r)
		crypt_dump(cd);

	crypt_free(cd);
	return r;
}

static struct action_type {
	const char *type;
	int (*handler)(int);
	int required_action_argc;
	const char *arg_desc;
	const char *desc;
} action_types[] = {
	{ "format",	action_format, 1, N_("<integrity_device>"),N_("format device") },
	{ "open",	action_open,   2, N_("<integrity_device> <name>"),N_("open device as <name>") },
	{ "close",	action_close,  1, N_("<name>"),N_("close device (deactivate and remove mapping)") },
	{ "status",	action_status, 1, N_("<name>"),N_("show active device status") },
	{ "dump",	action_dump,   1, N_("<integrity_device>"),N_("show on-disk information") },
	{ NULL, NULL, 0, NULL, NULL }
};

static void help(poptContext popt_context,
		 enum poptCallbackReason reason __attribute__((unused)),
		 struct poptOption *key,
		 const char *arg __attribute__((unused)),
		 void *data __attribute__((unused)))
{
	struct action_type *action;

	if (key->shortName == '?') {
		log_std("%s %s\n", PACKAGE_INTEGRITY, PACKAGE_VERSION);
		poptPrintHelp(popt_context, stdout, 0);
		log_std(_("\n"
			 "<action> is one of:\n"));
		for(action = action_types; action->type; action++)
			log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
		log_std(_("\n"
			 "<name> is the device to create under %s\n"
			 "<integrity_device> is the device containing data with integrity tags\n"),
			crypt_get_dir());

		log_std(_("\nDefault compiled-in dm-integrity parameters:\n"
			  "\tTag size: %u bytes, Checksum algorithm: %s\n"),
			  DEFAULT_TAG_SIZE, DEFAULT_ALG_NAME);
		exit(EXIT_SUCCESS);
	} else
		usage(popt_context, EXIT_SUCCESS, NULL, NULL);
}

static int run_action(struct action_type *action)
{
	int r;

	log_dbg("Running command %s.", action->type);

	r = action->handler(0);

	show_status(r);
	return translate_errno(r);
}
static int backup_luks_headers(struct reenc_ctx *rc)
{
	struct crypt_device *cd = NULL;
	struct crypt_params_luks1 params = {0};
	char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
	char *old_key = NULL;
	size_t old_key_size;
	int r;

	log_dbg("Creating LUKS header backup for device %s.", rc->device);

	if ((r = crypt_init(&cd, rc->device)) ||
	    (r = crypt_load(cd, CRYPT_LUKS1, NULL)))
		goto out;

	crypt_set_confirm_callback(cd, NULL, NULL);
	if ((r = crypt_header_backup(cd, CRYPT_LUKS1, rc->header_file_org)))
		goto out;
	log_verbose(_("LUKS header backup of device %s created.\n"), rc->device);

	/* For decrypt, new header will be fake one, so we are done here. */
	if (rc->reencrypt_mode == DECRYPT)
		goto out;

	if ((r = create_empty_header(rc->header_file_new, rc->header_file_org,
		crypt_get_data_offset(cd))))
		goto out;

	params.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
	params.data_alignment = crypt_get_data_offset(cd);
	params.data_alignment += ROUND_SECTOR(opt_reduce_size);
	params.data_device = rc->device;

	if (opt_cipher) {
		r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
		if (r < 0) {
			log_err(_("No known cipher specification pattern detected.\n"));
			goto out;
		}
	}

	if (opt_keep_key) {
		log_dbg("Keeping key from old header.");
		old_key_size  = crypt_get_volume_key_size(cd);
		old_key = crypt_safe_alloc(old_key_size);
		if (!old_key) {
			r = -ENOMEM;
			goto out;
		}
		r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, old_key, &old_key_size,
			rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen);
		if (r < 0)
			goto out;
	}

	r = create_new_header(rc,
		opt_cipher ? cipher : crypt_get_cipher(cd),
		opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd),
		crypt_get_uuid(cd),
		old_key,
		opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd),
		&params);
out:
	crypt_free(cd);
	crypt_safe_free(old_key);
	if (r)
		log_err(_("Creation of LUKS backup headers failed.\n"));
	return r;
}
Exemple #10
0
int crypt_keyfile_device_read(struct crypt_device *cd,  const char *keyfile,
			      char **key, size_t *key_size_read,
			      uint64_t keyfile_offset, size_t keyfile_size_max,
			      uint32_t flags)
{
	int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
	int r = -EINVAL, newline;
	char *pass = NULL;
	size_t buflen, i;
	uint64_t file_read_size;
	struct stat st;

	if (!key || !key_size_read)
		return -EINVAL;

	*key = NULL;
	*key_size_read = 0;

	fd = keyfile ? open(keyfile, O_RDONLY) : STDIN_FILENO;
	if (fd < 0) {
		log_err(cd, _("Failed to open key file."));
		return -EINVAL;
	}

	if (isatty(fd)) {
		log_err(cd, _("Cannot read keyfile from a terminal."));
		r = -EINVAL;
		goto out_err;
	}

	/* If not requested otherwise, we limit input to prevent memory exhaustion */
	if (keyfile_size_max == 0) {
		keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
		unlimited_read = 1;
		/* use 4k for buffer (page divisor but avoid huge pages) */
		buflen = 4096 - sizeof(struct safe_allocation);
	} else
		buflen = keyfile_size_max;

	regular_file = 0;
	if (keyfile) {
		if (stat(keyfile, &st) < 0) {
			log_err(cd, _("Failed to stat key file."));
			goto out_err;
		}
		if (S_ISREG(st.st_mode)) {
			regular_file = 1;
			file_read_size = (uint64_t)st.st_size;

			if (keyfile_offset > file_read_size) {
				log_err(cd, _("Cannot seek to requested keyfile offset."));
				goto out_err;
			}
			file_read_size -= keyfile_offset;

			/* known keyfile size, alloc it in one step */
			if (file_read_size >= (uint64_t)keyfile_size_max)
				buflen = keyfile_size_max;
			else if (file_read_size)
				buflen = file_read_size;
		}
	}

	pass = crypt_safe_alloc(buflen);
	if (!pass) {
		log_err(cd, _("Out of memory while reading passphrase."));
		goto out_err;
	}

	/* Discard keyfile_offset bytes on input */
	if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
		log_err(cd, _("Cannot seek to requested keyfile offset."));
		goto out_err;
	}

	for (i = 0, newline = 0; i < keyfile_size_max; i += char_read) {
		if (i == buflen) {
			buflen += 4096;
			pass = crypt_safe_realloc(pass, buflen);
			if (!pass) {
				log_err(cd, _("Out of memory while reading passphrase."));
				r = -ENOMEM;
				goto out_err;
			}
		}

		if (flags & CRYPT_KEYFILE_STOP_EOL) {
			/* If we should stop on newline, we must read the input
			 * one character at the time. Otherwise we might end up
			 * having read some bytes after the newline, which we
			 * promised not to do.
			 */
			char_to_read = 1;
		} else {
			/* char_to_read = min(keyfile_size_max - i, buflen - i) */
			char_to_read = keyfile_size_max < buflen ?
				keyfile_size_max - i : buflen - i;
		}
		char_read = read_buffer(fd, &pass[i], char_to_read);
		if (char_read < 0) {
			log_err(cd, _("Error reading passphrase."));
			r = -EPIPE;
			goto out_err;
		}

		if (char_read == 0)
			break;
		/* Stop on newline only if not requested read from keyfile */
		if ((flags & CRYPT_KEYFILE_STOP_EOL) && pass[i] == '\n') {
			newline = 1;
			pass[i] = '\0';
			break;
		}
	}

	/* Fail if piped input dies reading nothing */
	if (!i && !regular_file && !newline) {
		log_dbg("Nothing read on input.");
		r = -EPIPE;
		goto out_err;
	}

	/* Fail if we exceeded internal default (no specified size) */
	if (unlimited_read && i == keyfile_size_max) {
		log_err(cd, _("Maximum keyfile size exceeded."));
		goto out_err;
	}

	if (!unlimited_read && i != keyfile_size_max) {
		log_err(cd, _("Cannot read requested amount of data."));
		goto out_err;
	}

	*key = pass;
	*key_size_read = i;
	r = 0;
out_err:
	if (fd != STDIN_FILENO)
		close(fd);

	if (r)
		crypt_safe_free(pass);
	return r;
}