Exemple #1
0
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
{
	int hash_size = crypt_hash_size(hash_name);
	unsigned int digest_size;
	unsigned int i, blocks, padding;

	if (hash_size <= 0)
		return 1;
	digest_size = hash_size;

	blocks = size / digest_size;
	padding = size % digest_size;

	for (i = 0; i < blocks; i++)
		if(hash_buf(src + digest_size * i,
			    dst + digest_size * i,
			    i, (size_t)digest_size, hash_name))
			return 1;

	if(padding)
		if(hash_buf(src + digest_size * i,
			    dst + digest_size * i,
			    i, (size_t)padding, hash_name))
			return 1;

	return 0;
}
Exemple #2
0
static int hash(const char *hash_name, size_t key_size, char *key,
		size_t passphrase_size, const char *passphrase)
{
	struct crypt_hash *md = NULL;
	size_t len;
	int round, i, r = 0;

	if (crypt_hash_init(&md, hash_name))
		return -ENOENT;

	len = crypt_hash_size(hash_name);

	for(round = 0; key_size && !r; round++) {
		/* hack from hashalot to avoid null bytes in key */
		for(i = 0; i < round; i++)
			if (crypt_hash_write(md, "A", 1))
				r = 1;

		if (crypt_hash_write(md, passphrase, passphrase_size))
			r = 1;

		if (len > key_size)
			len = key_size;

		if (crypt_hash_final(md, key, len))
			r = 1;

		key += len;
		key_size -= len;
	}

	crypt_hash_destroy(md);
	return r;
}
/*
 * Compare hash (checksum) of on-disk and in-memory header.
 */
static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
			      const char *json_area, size_t json_len)
{
	struct luks2_hdr_disk hdr_tmp;
	int hash_size, r;

	hash_size = crypt_hash_size(alg);
	if (hash_size <= 0)
		return -EINVAL;

	/* Copy header and zero checksum. */
	memcpy(&hdr_tmp, hdr_disk, LUKS2_HDR_BIN_LEN);
	memset(&hdr_tmp.csum, 0, sizeof(hdr_tmp.csum));

	r = hdr_checksum_calculate(alg, &hdr_tmp, json_area, json_len);
	if (r < 0)
		return r;

	log_dbg_checksum(hdr_disk->csum, alg, "on-disk");
	log_dbg_checksum(hdr_tmp.csum, alg, "in-memory");

	if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size))
		return -EINVAL;

	return 0;
}
static void log_dbg_checksum(const uint8_t *csum, const char *csum_alg, const char *info)
{
	char csum_txt[2*LUKS2_CHECKSUM_L+1];
	int i;

	for (i = 0; i < crypt_hash_size(csum_alg); i++)
		snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]);
	csum_txt[i*2+1] = '\0'; /* Just to be safe, sprintf should write \0 there. */

	log_dbg("Checksum:%s (%s)", &csum_txt[0], info);
}
/*
 * Calculate hash (checksum) of |LUKS2_bin|LUKS2_JSON_area| from in-memory structs.
 * LUKS2 on-disk header contains uniques salt both for primary and secondary header.
 * Checksum is always calculated with zeroed checksum field in binary header.
 */
static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_disk,
				  const char *json_area, size_t json_len)
{
	struct crypt_hash *hd = NULL;
	int hash_size, r;

	hash_size = crypt_hash_size(alg);
	if (hash_size <= 0 || crypt_hash_init(&hd, alg))
		return -EINVAL;

	/* Binary header, csum zeroed. */
	r = crypt_hash_write(hd, (char*)hdr_disk, LUKS2_HDR_BIN_LEN);

	/* JSON area (including unused space) */
	if (!r)
		r = crypt_hash_write(hd, json_area, json_len);

	if (!r)
		r = crypt_hash_final(hd, (char*)hdr_disk->csum, (size_t)hash_size);

	crypt_hash_destroy(hd);
	return r;
}
/* HMAC */
int crypt_hmac_size(const char *name)
{
	return crypt_hash_size(name);
}
static int TCRYPT_init_hdr(struct crypt_device *cd,
			   struct tcrypt_phdr *hdr,
			   struct crypt_params_tcrypt *params)
{
	unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {};
	size_t passphrase_size;
	char *key;
	unsigned int i, skipped = 0;
	int r = -EPERM;

	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;

	if (params->passphrase_size > TCRYPT_KEY_POOL_LEN) {
		log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded.\n"),
			      TCRYPT_KEY_POOL_LEN);
		goto out;
	}

	/* Calculate pool content from keyfiles */
	for (i = 0; i < params->keyfiles_count; i++) {
		r = TCRYPT_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++) {
		if (!(params->flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_kdf[i].legacy)
			continue;
		if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt)
			continue;
		/* 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,
				(char*)pwd, passphrase_size,
				hdr->salt, TCRYPT_HDR_SALT_LEN,
				key, TCRYPT_HDR_KEY_LEN,
				tcrypt_kdf[i].iterations);
		if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) {
			log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping.\n"),
				      tcrypt_kdf[i].hash);
			continue;
		}
		if (r < 0)
			break;

		/* Decrypt header */
		r = TCRYPT_decrypt_hdr(cd, hdr, key, params->flags);
		if (r == -ENOENT) {
			skipped++;
			r = -EPERM;
		}
		if (r != -EPERM)
			break;
	}

	if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) {
		log_err(cd, _("Required kernel crypto interface not available.\n"));
#ifdef ENABLE_AF_ALG
		log_err(cd, _("Ensure you have algif_skcipher kernel module loaded.\n"));
#endif
	}
	if (r < 0)
		goto out;

	r = TCRYPT_hdr_from_disk(hdr, params, i, r);
	if (!r) {
		log_dbg("TCRYPT: Magic: %s, Header version: %d, req. %d, sector %d"
			", mk_offset %" PRIu64 ", hidden_size %" PRIu64
			", volume size %" PRIu64, tcrypt_kdf[i].veracrypt ?
			VCRYPT_HDR_MAGIC : TCRYPT_HDR_MAGIC,
			(int)hdr->d.version, (int)hdr->d.version_tc, (int)hdr->d.sector_size,
			hdr->d.mk_offset, hdr->d.hidden_volume_size, hdr->d.volume_size);
		log_dbg("TCRYPT: Header cipher %s-%s, key size %zu",
			params->cipher, params->mode, params->key_size);
	}
out:
	crypt_memzero(pwd, TCRYPT_KEY_POOL_LEN);
	if (key)
		crypt_memzero(key, TCRYPT_HDR_KEY_LEN);
	free(key);
	return r;
}
Exemple #8
0
/* Read verity superblock from disk */
int VERITY_read_sb(struct crypt_device *cd,
		   uint64_t sb_offset,
		   char **uuid_string,
		   struct crypt_params_verity *params)
{
	struct device *device = crypt_metadata_device(cd);
	int bsize = device_block_size(device);
	struct verity_sb sb = {};
	ssize_t hdr_size = sizeof(struct verity_sb);
	int devfd = 0, sb_version;

	log_dbg("Reading VERITY header of size %zu on device %s, offset %" PRIu64 ".",
		sizeof(struct verity_sb), device_path(device), sb_offset);

	if (params->flags & CRYPT_VERITY_NO_HEADER) {
		log_err(cd, _("Verity device %s doesn't use on-disk header.\n"),
			device_path(device));
		return -EINVAL;
	}

	if (sb_offset % 512) {
		log_err(cd, _("Unsupported VERITY hash offset.\n"));
		return -EINVAL;
	}

	devfd = device_open(device, O_RDONLY);
	if(devfd == -1) {
		log_err(cd, _("Cannot open device %s.\n"), device_path(device));
		return -EINVAL;
	}

	if(lseek(devfd, sb_offset, SEEK_SET) < 0 ||
	   read_blockwise(devfd, bsize, &sb, hdr_size) < hdr_size) {
		close(devfd);
		return -EIO;
	}
	close(devfd);

	if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) {
		log_err(cd, _("Device %s is not a valid VERITY device.\n"),
			device_path(device));
		return -EINVAL;
	}

	sb_version = le32_to_cpu(sb.version);
	if (sb_version != 1) {
		log_err(cd, _("Unsupported VERITY version %d.\n"), sb_version);
		return -EINVAL;
	}
	params->hash_type = le32_to_cpu(sb.hash_type);
	if (params->hash_type > VERITY_MAX_HASH_TYPE) {
		log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
		return -EINVAL;
	}

	params->data_block_size = le32_to_cpu(sb.data_block_size);
	params->hash_block_size = le32_to_cpu(sb.hash_block_size);
	if (VERITY_BLOCK_SIZE_OK(params->data_block_size) ||
	    VERITY_BLOCK_SIZE_OK(params->hash_block_size)) {
		log_err(cd, _("Unsupported VERITY block size.\n"));
		return -EINVAL;
	}
	params->data_size = le64_to_cpu(sb.data_blocks);

	params->hash_name = strndup((const char*)sb.algorithm, sizeof(sb.algorithm));
	if (!params->hash_name)
		return -ENOMEM;
	if (crypt_hash_size(params->hash_name) <= 0) {
		log_err(cd, _("Hash algorithm %s not supported.\n"),
			params->hash_name);
		free(CONST_CAST(char*)params->hash_name);
		return -EINVAL;
	}

	params->salt_size = le16_to_cpu(sb.salt_size);
	if (params->salt_size > sizeof(sb.salt)) {
		log_err(cd, _("VERITY header corrupted.\n"));
		free(CONST_CAST(char*)params->hash_name);
		return -EINVAL;
	}
	params->salt = malloc(params->salt_size);
	if (!params->salt) {
		free(CONST_CAST(char*)params->hash_name);
		return -ENOMEM;
	}
	memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);

	if ((*uuid_string = malloc(40)))
		uuid_unparse(sb.uuid, *uuid_string);

	params->hash_area_offset = sb_offset;
	return 0;
}