[RFC] Partial support for reading DiskCryptor volumes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

Back in June, I wrote to the mailing list seeking some help with
reverse-engineering the DiskCryptor volume format [1].

Since then, I have implemented decryption of the volume header (for all
cipher combinations, with autodetection) and would like to know whether
you would be interested in merging support for opening DiskCryptor
volumes once it is ready.

The DiskCryptor development has largely stalled, with the last beta
release in April 2020. Releases by DavidXanatos have the following
problem [3]:

>        The Disk Cryptor driver needed to be updated, and since the
>        ReactOS foundation no longer offer a driver signing service, I
>        head to use a leaked code signing certificate I found laying
>        around the Internets. This means some anti malware applications
>        may wrongfully flag it as potentially dangerous.

I'm attaching my current code, which can also be browsed on:
https://github.com/matjon/cryptsetup/tree/dcryptor_support/lib/dcryptor

The code is somewhat similar to ./lib/tcrypt/tcrypt.c as DiskCryptor was
inspired by TrueCrypt. It uses, however, a different volume layout (the
first 2048 bytes of the underlying filesystem are relocated to a
different place on the partition [2]).

Greetings,
Mateusz

[1] see thread from "Thu, 3 Jun 2021 12:05:28 +0200"
   https://lore.kernel.org/dm-crypt/7d911d89-aea8-5d2b-65c4-051de6f54955@xxxxx/T/

[2] https://diskcryptor.org/volume/

[3] https://github.com/DavidXanatos/DiskCryptor/releases

---
 lib/Makemodule.am                             |   2 +
 lib/dcryptor/dcryptor.c                       | 424 ++++++++++++++++++
 lib/dcryptor/dcryptor.h                       |  66 +++
 lib/libcryptsetup.h                           |  21 +-
 lib/setup.c                                   |  79 +++-
 src/cryptsetup.c                              |  71 +++
 tests/diskcryptor/password.txt                |   1 +
 tests/diskcryptor/volume_aes.bin              | Bin 0 -> 8388608 bytes
 tests/diskcryptor/volume_aes_twofish.bin      | Bin 0 -> 8388608 bytes
 .../volume_aes_twofish_serpent.bin            | Bin 0 -> 8388608 bytes
 tests/diskcryptor/volume_serpent.bin          | Bin 0 -> 8388608 bytes
 tests/diskcryptor/volume_serpent_aes.bin      | Bin 0 -> 8388608 bytes
 tests/diskcryptor/volume_twofish.bin          | Bin 0 -> 8388608 bytes
 tests/diskcryptor/volume_twofish_serpent.bin  | Bin 0 -> 8388608 bytes
 14 files changed, 662 insertions(+), 2 deletions(-)
 create mode 100644 lib/dcryptor/dcryptor.c
 create mode 100644 lib/dcryptor/dcryptor.h
 create mode 100644 tests/diskcryptor/password.txt
 create mode 100755 tests/diskcryptor/volume_aes.bin
 create mode 100755 tests/diskcryptor/volume_aes_twofish.bin
 create mode 100755 tests/diskcryptor/volume_aes_twofish_serpent.bin
 create mode 100755 tests/diskcryptor/volume_serpent.bin
 create mode 100755 tests/diskcryptor/volume_serpent_aes.bin
 create mode 100755 tests/diskcryptor/volume_twofish.bin
 create mode 100755 tests/diskcryptor/volume_twofish_serpent.bin

diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index e9b250e7..3b5529b6 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -76,6 +76,8 @@ libcryptsetup_la_SOURCES = \
 	lib/loopaes/loopaes.c		\
 	lib/tcrypt/tcrypt.h		\
 	lib/tcrypt/tcrypt.c		\
+	lib/dcryptor/dcryptor.h	        \
+	lib/dcryptor/dcryptor.c	        \
 	lib/luks1/af.h			\
 	lib/luks1/af.c			\
 	lib/luks1/keyencryption.c	\
diff --git a/lib/dcryptor/dcryptor.c b/lib/dcryptor/dcryptor.c
new file mode 100644
index 00000000..5e2df97c
--- /dev/null
+++ b/lib/dcryptor/dcryptor.c
@@ -0,0 +1,424 @@
+/*
+ * DiskCryptor-compatible volume handling
+ *
+ * Copyright (C) 2021 Mateusz Jończyk
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <iconv.h>
+
+#include "libcryptsetup.h"
+#include "dcryptor.h"
+#include "internal.h"
+
+// copied from lib/bitlk/bitlk.c
+static int passphrase_to_utf16(struct crypt_device *cd, char *input, size_t inlen, char **out)
+{
+	char *outbuf = NULL;
+	iconv_t ic;
+	size_t ic_inlen = inlen;
+	size_t ic_outlen = inlen * 2;
+	char *ic_outbuf = NULL;
+	size_t r = 0;
+
+	if (inlen == 0)
+		return r;
+
+	outbuf = crypt_safe_alloc(inlen * 2);
+	if (outbuf == NULL)
+		return -ENOMEM;
+
+	memset(outbuf, 0, inlen * 2);
+	ic_outbuf = outbuf;
+
+	ic = iconv_open("UTF-16LE", "UTF-8");
+	r = iconv(ic, &input, &ic_inlen, &ic_outbuf, &ic_outlen);
+	iconv_close(ic);
+
+	if (r == 0) {
+		*out = outbuf;
+	} else {
+		*out = NULL;
+		crypt_safe_free(outbuf);
+		log_dbg(cd, "Failed to convert passphrase: %s", strerror(errno));
+		r = -errno;
+	}
+
+	return r;
+}
+
+
+// These structures and list heavily by a similar list in tcrypt/tcrypt.c
+struct dcryptor_alg {
+		const char *name;
+		unsigned int key_offset;
+		unsigned int iv_offset;
+};
+
+struct dcryptor_algs {
+	uint32_t alg_id;       // as used in the volume header
+	unsigned int chain_length;
+	const char *long_name;
+	struct dcryptor_alg cipher[3];
+};
+
+static struct dcryptor_algs dcryptor_cipher[] = {
+	{ 0x0, 1, "aes",
+		{{"aes",      0, 32}}},
+	{ 0x1, 1, "twofish",
+		{{"twofish",  0, 32}}},
+	{ 0x2, 1, "serpent",
+		{{"serpent",  0, 32}}},
+	{ 0x3, 2, "aes-twofish",
+		{{"aes",     32, 32*3},
+		{"twofish",   0, 32*2}}},
+	{ 0x4, 2, "twofish-serpent",
+		{{"twofish", 32, 32*3},
+		{"serpent",   0, 32*2}}},
+	{ 0x5, 2, "serpent-aes",
+		{{"serpent", 32, 32*3},
+		{"aes",       0, 32*2}}},
+	{ 0x6, 3, "aes-twofish-serpent", {
+		{"aes",    32*2, 32*5},
+		{"twofish",  32, 32*4},
+		{"serpent",   0, 32*3},
+		}},
+	{}
+};
+
+static void hexdump_buffer(FILE *stream, const unsigned char *buffer,
+		size_t buffer_size, const int bytes_per_line)
+{
+	// TODO: make the function more readable
+	// TODO: replace fprintf with something faster, like sprintf
+	for (size_t i = 0; i < buffer_size; i+=bytes_per_line) {
+		fprintf(stream, "%08x  ", (unsigned int) i);
+
+		for (size_t j = i; j < i + bytes_per_line && j < buffer_size; j++) {
+			fprintf(stream, "%02x ", (unsigned int) buffer[j]);
+		}
+		// last line padding
+		for (size_t j = buffer_size; j < i + bytes_per_line; j++) {
+			fputs("   ", stream);
+		}
+
+		fprintf(stream, " |");
+		for (size_t j = i; j < i+bytes_per_line && j < buffer_size; j++) {
+			if (isprint(buffer[j])) {
+				fputc(buffer[j], stream);
+			} else {
+				fputc('.', stream);
+			}
+		}
+		// last line padding
+		for (size_t j = buffer_size; j < i+bytes_per_line; j++) {
+			fputs(" ", stream);
+		}
+		fprintf(stream, "|\n");
+	}
+}
+
+/*
+ * Checks if the header signature and CRC32 matches, to determine
+ * if the password is correct. Does not validate other header fields.
+ */
+static bool DCRYPTOR_is_correctly_decrypted(struct dcryptor_phdr *hdr)
+{
+	if (strncmp(hdr->signature, "DCRP", 4))
+		return false;
+
+	// DiskCryptor uses unmodified CRC-32
+	uint32_t header_crc = crypt_crc32(0xffffffff,
+			(const unsigned char*)hdr + 72, 2048-72);
+	// crypt_crc32() does not perform the final XOR
+	header_crc ^= 0xffffffff;
+
+	// TODO: big-endian architectures?
+	if (header_crc != hdr->crc32)
+		return false;
+
+	return true;
+}
+
+
+int DCRYPTOR_decrypt_hdr_one_cipher(char *key,
+		struct dcryptor_enchdr *dest,
+		struct dcryptor_enchdr *source,
+		struct dcryptor_alg *alg)
+{
+	struct crypt_cipher *cipher;
+	char *key_one;
+	int r;
+	char iv[16] = {};
+
+	if (posix_memalign((void*)&key_one, crypt_getpagesize(), DCRYPTOR_KEY_LEN))
+		return -ENOMEM;
+
+	memcpy(key_one, key + alg->key_offset, 32);
+	memcpy(key_one+32, key + alg->iv_offset, 32);
+
+	r = crypt_cipher_init(&cipher, alg->name, "xts", key_one, 64);
+	if (r)
+		goto exit;
+
+	// TODO: what about 4kB sectors?
+	for (int i = 0; i < DCRYPTOR_HDR_LEN / 512; i++) {
+		iv[0] = i+1;
+		r = crypt_cipher_decrypt(cipher,
+			(const char *)source + i * 512,
+			(char *)dest + i * 512,
+			512,
+			iv, 16);
+
+	}
+	crypt_cipher_destroy(cipher);
+
+exit:
+	if (key_one)
+		crypt_safe_memzero(key_one, DCRYPTOR_KEY_LEN);
+
+	free(key_one);
+	return r;
+}
+
+int DCRYPTOR_decrypt_hdr_one_combination(char *key,
+		struct dcryptor_enchdr *enchdr,
+		struct dcryptor_phdr *hdr,
+		struct dcryptor_algs *algs)
+{
+	int i;
+	int r;
+	struct dcryptor_enchdr *temp_hdr;
+
+	if (posix_memalign((void*)&temp_hdr, crypt_getpagesize(),
+				DCRYPTOR_HDR_LEN)) {
+		return -ENOMEM;
+	}
+
+	memcpy(temp_hdr, enchdr, DCRYPTOR_HDR_LEN);
+
+	for (i = 0; i < algs->chain_length; i++) {
+		r = DCRYPTOR_decrypt_hdr_one_cipher(key,
+				(struct dcryptor_enchdr *) hdr,
+				temp_hdr, &algs->cipher[i]);
+		if (r)
+			goto exit;
+
+		memcpy(temp_hdr, hdr, DCRYPTOR_HDR_LEN);
+	}
+
+	if (DCRYPTOR_is_correctly_decrypted(hdr))
+		r = 0;
+	else
+		r = 1;
+
+exit:
+
+	if (temp_hdr)
+		crypt_safe_memzero(temp_hdr, DCRYPTOR_HDR_LEN);
+
+	free(temp_hdr);
+	return r;
+}
+
+
+// Try all combinations that have a specific chain_length, calculating pbkdf2
+// once
+int DCRYPTOR_decrypt_hdr_one_chain_length(
+		struct crypt_device *cd,
+		struct dcryptor_enchdr *enchdr,
+		struct dcryptor_phdr *hdr,
+		char *pwd_utf16,
+		int pwd_utf16_length,
+		int chain_length,
+		int *found_combination)
+{
+	char *key;
+	int r;
+	int ret = 1;
+	int i;
+
+	if (posix_memalign((void*)&key, crypt_getpagesize(), DCRYPTOR_KEY_LEN * chain_length))
+		return -ENOMEM;
+
+	r = crypt_pbkdf("pbkdf2", "sha512",
+			pwd_utf16, pwd_utf16_length,
+			enchdr->salt, DCRYPTOR_SALT_LEN,
+			key, DCRYPTOR_KEY_LEN * chain_length,
+			1000, 0, 0);
+
+	for (i = 0; dcryptor_cipher[i].chain_length; i++) {
+		if (dcryptor_cipher[i].chain_length != chain_length)
+			continue;
+
+		r = DCRYPTOR_decrypt_hdr_one_combination(key, enchdr, hdr,
+			&dcryptor_cipher[i]);
+		if (r == 0) {
+			// found!
+			ret = 0;
+			*found_combination = i;
+			break;
+		}
+
+		if (r < 0) {
+			// error!
+			ret = r;
+			break;
+		}
+	}
+
+	if (key)
+		crypt_safe_memzero(key, DCRYPTOR_KEY_LEN * chain_length);
+
+	free(key);
+	return ret;
+}
+
+int DCRYPTOR_decrypt_hdr(struct crypt_device *cd,
+			   struct dcryptor_enchdr *enchdr,
+			   struct dcryptor_phdr *hdr,
+			   struct crypt_params_dcryptor *params)
+{
+	int r;
+	int i;
+	int found_combination;
+
+	assert(sizeof(struct dcryptor_enchdr) == DCRYPTOR_HDR_LEN);
+	assert(sizeof(struct dcryptor_phdr) == DCRYPTOR_HDR_LEN);
+
+	char *utf16Password = NULL;
+	r = passphrase_to_utf16(cd, CONST_CAST(char *) params->passphrase, params->passphrase_size, &utf16Password);
+	// TODO: check r
+
+	for (i = 1 ; i <= 3; i++) {
+		r = DCRYPTOR_decrypt_hdr_one_chain_length(cd, enchdr, hdr,
+			utf16Password, params->passphrase_size * 2,
+			i,
+			&found_combination);
+
+		if (r <= 0)
+			break;
+	}
+	// TODO: if (r < 0) ...
+
+	if (r == 0) {
+		log_std(cd, "DONE\n");
+		// hexprint(cd, hdr, 2048, " ");
+
+		hexdump_buffer(stderr, (const unsigned char *)hdr, 2048, 16);
+	}
+
+	// TODO: little-endian vs big-endian
+
+	return r;
+}
+
+/*
+
+int DCRYPTOR_decrypt_sector(struct crypt_device *cd,
+		struct dcryptor_phdr *hdr,
+		uint64_t sector_number)
+{
+	int r;
+	struct crypt_cipher *cipher;
+	char iv[16] = {};
+	char *sector = malloc(512);
+	char *sector_decrypted = malloc(512);
+
+	struct device *device = crypt_data_device(cd);
+	int devfd;
+	devfd = device_open(cd, device, O_RDONLY);
+	if (devfd < 0) {
+		device_free(cd, device);
+		log_err(cd, _("Cannot open device %s."), device_path(device));
+		return -EINVAL;
+	}
+
+	if (read_lseek_blockwise(devfd, device_block_size(cd, device),
+			device_alignment(device), sector, DCRYPTOR_HDR_LEN, sector_number * 512)
+			!= 512) {
+
+		device_free(cd, device);
+		log_err(cd, _("Cannot read device %s."), device_path(device));
+		return -EINVAL;
+	}
+
+	r = crypt_cipher_init(&cipher, "aes", "xts", hdr->key, 64);
+
+	for (int i = 16300; i <= 16400; i++) {
+		iv[0] = i % 256;
+		iv[1] = i / 256;
+
+		fprintf(stderr, "\n\ni=%d\n", i);
+
+		r = crypt_cipher_decrypt(cipher,
+			sector,
+			sector_decrypted,
+			512,
+			iv, 16);
+
+		hexdump_buffer(stderr, sector_decrypted, 512, 16);
+	}
+
+	free(sector);
+	free(sector_decrypted);
+
+	return 0;
+}
+*/
+
+int DCRYPTOR_read_phdr(struct crypt_device *cd,
+		     struct dcryptor_phdr *hdr,
+		     struct crypt_params_dcryptor *params)
+{
+	int r = 0;
+	int devfd;
+	struct device *device = crypt_data_device(cd);
+	struct dcryptor_enchdr *enchdr;
+
+	devfd = device_open(cd, device, O_RDONLY);
+	if (devfd < 0) {
+		device_free(cd, device);
+		log_err(cd, _("Cannot open device %s."), device_path(device));
+		return -EINVAL;
+	}
+
+	enchdr = malloc(sizeof(struct dcryptor_enchdr));
+	// TODO: if (enchdr == NULL)
+
+	if (read_lseek_blockwise(devfd, device_block_size(cd, device),
+			device_alignment(device), enchdr, DCRYPTOR_HDR_LEN, 0) == DCRYPTOR_HDR_LEN) {
+		r = DCRYPTOR_decrypt_hdr(cd, enchdr, hdr, params);
+
+		//DCRYPTOR_decrypt_sector(cd, hdr, 16380);
+	}
+
+	if (r < 0)
+		memset(hdr, 0, sizeof (*hdr));
+
+	free(enchdr);
+	return r;
+}
+
+// TODO: should I use xts-plain64, or possibly xts-plain?
diff --git a/lib/dcryptor/dcryptor.h b/lib/dcryptor/dcryptor.h
new file mode 100644
index 00000000..518ddb73
--- /dev/null
+++ b/lib/dcryptor/dcryptor.h
@@ -0,0 +1,66 @@
+/*
+ * DiskCryptor-compatible header definition
+ *
+ * Copyright (C) 2021 Mateusz Jończyk
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRYPTSETUP_DCRYPTOR_H
+#define _CRYPTSETUP_DCRYPTOR_H
+
+#define DCRYPTOR_HDR_LEN    2048
+#define DCRYPTOR_SALT_LEN 64
+
+struct dcryptor_enchdr {
+	char salt[DCRYPTOR_SALT_LEN];
+	char encrypted[DCRYPTOR_HDR_LEN - DCRYPTOR_SALT_LEN];
+} __attribute__((__packed__));
+
+#define DCRYPTOR_KEY_LEN 64
+// Header provides space for separate keys for 4 chained ciphers
+#define DCRYPTOR_MAX_KEYS 4
+#define DCRYPTOR_MAX_CHAINED_KEYS_LEN DCRYPTOR_HDR_KEY_LEN * DCRYPTOR_MAX_KEYS
+
+struct dcryptor_phdr {
+	char _trash[DCRYPTOR_SALT_LEN];
+	char signature[4];
+	uint32_t crc32;
+	uint16_t header_version;
+	uint32_t flags;
+	uint32_t uuid;
+
+	uint32_t alg_id;
+	char key[DCRYPTOR_MAX_KEYS][DCRYPTOR_KEY_LEN];
+	uint32_t previous_alg_id;
+	char previous_key[DCRYPTOR_MAX_KEYS][DCRYPTOR_KEY_LEN];
+
+	uint64_t relocation_offset;
+	uint64_t data_size;
+	uint64_t encrypted_size;
+	uint8_t wipe_mode;
+
+	char padding[1421];
+} __attribute__((__packed__));
+
+
+struct crypt_device;
+struct crypt_params_dcryptor;
+
+int DCRYPTOR_read_phdr(struct crypt_device *cd,
+		     struct dcryptor_phdr *hdr,
+		     struct crypt_params_dcryptor *params);
+
+#endif
diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h
index 4b66fe04..1efb3886 100644
--- a/lib/libcryptsetup.h
+++ b/lib/libcryptsetup.h
@@ -421,6 +421,8 @@ int crypt_get_metadata_size(struct crypt_device *cd,
 #define CRYPT_VERITY "VERITY"
 /** TCRYPT (TrueCrypt-compatible and VeraCrypt-compatible) mode */
 #define CRYPT_TCRYPT "TCRYPT"
+/** DiskCryptor */
+#define CRYPT_DCRYPTOR "DCRYPTOR"
 /** INTEGRITY dm-integrity device */
 #define CRYPT_INTEGRITY "INTEGRITY"
 /** BITLK (BitLocker-compatible mode) */
@@ -553,6 +555,23 @@ struct crypt_params_tcrypt {
  */
 #define CRYPT_TCRYPT_VERA_MODES      (1 << 4)
 
+/**
+ *
+ * Structure used as parameter for DiskCryptor device type.
+ *
+ * @see crypt_load
+ *
+ */
+struct crypt_params_dcryptor {
+	const char *passphrase;    /**< passphrase to unlock header (input only) */
+	size_t passphrase_size;    /**< passphrase size (input only) */
+	const char **keyfiles;     /**< NOT IMPLEMENTED YET */
+	unsigned int keyfiles_count;/**< NOT IMPLEMENTED YET */
+	const char *cipher;        /**< cipher chain c1[-c2[-c3]] */
+	size_t key_size;           /**< key size in bytes (the whole chain) */
+	uint32_t flags;            /**< CRYPT_DISKCRYPTOR* flags */
+};
+
 /**
  *
  * Structure used as parameter for dm-integrity device type.
@@ -2256,7 +2275,7 @@ int crypt_token_register(const crypt_token_handler *handler);
 
 /**
  * Report external token handlers (plugins) support
- 
+
  * @return @e 0 when enabled or negative errno value otherwise.
  */
 int crypt_token_external_support(void);
diff --git a/lib/setup.c b/lib/setup.c
index a044b878..a1f97b8a 100644
--- a/lib/setup.c
+++ b/lib/setup.c
@@ -34,6 +34,7 @@
 #include "loopaes/loopaes.h"
 #include "verity/verity.h"
 #include "tcrypt/tcrypt.h"
+#include "dcryptor/dcryptor.h"
 #include "integrity/integrity.h"
 #include "bitlk/bitlk.h"
 #include "utils_device_locking.h"
@@ -102,6 +103,10 @@ struct crypt_device {
 		struct crypt_params_tcrypt params;
 		struct tcrypt_phdr hdr;
 	} tcrypt;
+	struct { /* used in CRYPT_DCRYPTOR */
+		struct crypt_params_dcryptor params;
+		struct dcryptor_phdr hdr;
+	} dcryptor;
 	struct { /* used in CRYPT_INTEGRITY */
 		struct crypt_params_integrity params;
 		struct volume_key *journal_mac_key;
@@ -313,6 +318,11 @@ static int isTCRYPT(const char *type)
 	return (type && !strcmp(CRYPT_TCRYPT, type));
 }
 
+static int isDCRYPTOR(const char *type)
+{
+	return (type && !strcmp(CRYPT_DCRYPTOR, type));
+}
+
 static int isINTEGRITY(const char *type)
 {
 	return (type && !strcmp(CRYPT_INTEGRITY, type));
@@ -658,6 +668,7 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
 
 	if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) &&
 	    !isINTEGRITY(cd->type) && !isTCRYPT(cd->type)) {
+                // DiskCryptor - no support
 		log_err(cd, _("This operation is not supported for this device type."));
 		return -EINVAL;
 	}
@@ -870,6 +881,36 @@ static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcryp
 	return r;
 }
 
+static int _crypt_load_dcryptor(struct crypt_device *cd, struct crypt_params_dcryptor *params)
+{
+	int r;
+
+	if (!params)
+		return -EINVAL;
+
+	r = init_crypto(cd);
+	if (r < 0)
+		return r;
+
+	memcpy(&cd->u.dcryptor.params, params, sizeof(*params));
+
+	r = DCRYPTOR_read_phdr(cd, &cd->u.dcryptor.hdr, &cd->u.dcryptor.params);
+
+	cd->u.dcryptor.params.passphrase = NULL;
+	cd->u.dcryptor.params.passphrase_size = 0;
+	//cd->u.dcryptor.params.keyfiles = NULL;
+	//cd->u.dcryptor.params.keyfiles_count = 0;
+
+	if (r < 0)
+		return r;
+
+        // ???
+	if (!cd->type && !(cd->type = strdup(CRYPT_DCRYPTOR)))
+		return -ENOMEM;
+
+	return r;
+}
+
 static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verity *params)
 {
 	int r;
@@ -1038,6 +1079,12 @@ int crypt_load(struct crypt_device *cd,
 			return -EINVAL;
 		}
 		r = _crypt_load_tcrypt(cd, params);
+	} else if (isDCRYPTOR(requested_type)) {
+		if (cd->type && !isDCRYPTOR(cd->type)) {
+			log_dbg(cd, "Context is already initialized to type %s", cd->type);
+			return -EINVAL;
+		}
+		r = _crypt_load_dcryptor(cd, params);
 	} else if (isINTEGRITY(requested_type)) {
 		if (cd->type && !isINTEGRITY(cd->type)) {
 			log_dbg(cd, "Context is already initialized to type %s", cd->type);
@@ -2841,7 +2888,7 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
 	if (!cd || !cd->type || !name)
 		return -EINVAL;
 
-	if (isTCRYPT(cd->type) || isBITLK(cd->type)) {
+	if (isDCRYPTOR(cd->type) || isTCRYPT(cd->type) || isBITLK(cd->type)) {
 		log_err(cd, _("This operation is not supported for this device type."));
 		return -ENOTSUP;
 	}
@@ -4481,6 +4528,11 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
 			return 0;
 		r = TCRYPT_activate(cd, name, &cd->u.tcrypt.hdr,
 				    &cd->u.tcrypt.params, flags);
+
+	} else if (isDCRYPTOR(cd->type)) {
+                // TODO
+
+
 	} else if (isINTEGRITY(cd->type)) {
 		if (!name)
 			return 0;
@@ -4632,6 +4684,7 @@ int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t
 				r = LUKS2_deactivate(cd, name, hdr2, &dmd, flags);
 			else if (isTCRYPT(cd->type))
 				r = TCRYPT_deactivate(cd, name, flags);
+                        // TODO
 			else
 				r = dm_remove_device(cd, name, flags);
 			if (r < 0 && crypt_status(cd, name) == CRYPT_BUSY) {
@@ -4686,6 +4739,8 @@ int crypt_get_active_device(struct crypt_device *cd, const char *name,
 	if (cd && isTCRYPT(cd->type)) {
 		cad->offset	= TCRYPT_get_data_offset(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
 		cad->iv_offset	= TCRYPT_get_iv_offset(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
+
+        // TODO
 	} else {
 		while (tgt) {
 			if (tgt->type == DM_CRYPT && (min_offset > tgt->u.crypt.offset)) {
@@ -4778,6 +4833,8 @@ int crypt_volume_key_get(struct crypt_device *cd,
 				passphrase, passphrase_size, &vk);
 	} else if (isTCRYPT(cd->type)) {
 		r = TCRYPT_get_volume_key(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params, &vk);
+	} else if (isDCRYPTOR(cd->type)) {
+                // TODO
 	} else if (isVERITY(cd->type)) {
 		/* volume_key == root hash */
 		if (cd->u.verity.root_hash) {
@@ -4990,6 +5047,7 @@ int crypt_dump(struct crypt_device *cd)
 		return _verity_dump(cd);
 	else if (isTCRYPT(cd->type))
 		return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
+        // TODO
 	else if (isINTEGRITY(cd->type))
 		return INTEGRITY_dump(cd, crypt_data_device(cd), 0);
 	else if (isBITLK(cd->type))
@@ -5055,6 +5113,10 @@ const char *crypt_get_cipher(struct crypt_device *cd)
 	if (isTCRYPT(cd->type))
 		return cd->u.tcrypt.params.cipher;
 
+	if (isDCRYPTOR(cd->type))
+                // TODO
+                return NULL;
+
 	if (isBITLK(cd->type))
 		return cd->u.bitlk.params.cipher;
 
@@ -5088,6 +5150,10 @@ const char *crypt_get_cipher_mode(struct crypt_device *cd)
 	if (isTCRYPT(cd->type))
 		return cd->u.tcrypt.params.mode;
 
+	if (isDCRYPTOR(cd->type))
+                // TODO
+                return "xts-plain64";
+
 	if (isBITLK(cd->type))
 		return cd->u.bitlk.params.cipher_mode;
 
@@ -5231,6 +5297,10 @@ int crypt_get_volume_key_size(struct crypt_device *cd)
 	if (isTCRYPT(cd->type))
 		return cd->u.tcrypt.params.key_size;
 
+	if (isDCRYPTOR(cd->type))
+                // TODO
+                return 512;
+
 	if (isBITLK(cd->type))
 		return cd->u.bitlk.params.key_size / 8;
 
@@ -5418,6 +5488,8 @@ uint64_t crypt_get_data_offset(struct crypt_device *cd)
 	if (isBITLK(cd->type))
 		return cd->u.bitlk.params.volume_header_size / SECTOR_SIZE;
 
+        // TODO
+
 	return cd->data_offset;
 }
 
@@ -5435,6 +5507,8 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd)
 	if (isTCRYPT(cd->type))
 		return TCRYPT_get_iv_offset(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
 
+        // TODO
+
 	return 0;
 }
 
@@ -5653,6 +5727,9 @@ void *crypt_get_hdr(struct crypt_device *cd, const char *type)
 	if (isTCRYPT(cd->type))
 		return &cd->u.tcrypt;
 
+	if (isDCRYPTOR(cd->type))
+		return &cd->u.dcryptor;
+
 	return NULL;
 }
 
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index f321d8d2..e8921dbd 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -478,6 +478,73 @@ out:
 	return r;
 }
 
+static int dcryptor_load(struct crypt_device *cd, struct crypt_params_dcryptor *params)
+{
+	int r, tries, eperm = 0;
+
+	tries = _set_tries_tty();
+	do {
+		r = tools_get_key(NULL, CONST_CAST(char**)&params->passphrase,
+				  &params->passphrase_size, 0, 0, keyfile_stdin, ARG_UINT32(OPT_TIMEOUT_ID),
+				 _verify_passphrase(0), 0, cd);
+		if (r < 0)
+			continue;
+
+		r = crypt_load(cd, CRYPT_DCRYPTOR, params);
+
+		if (r == -EPERM) {
+			log_err(_("No device header detected with this passphrase."));
+			eperm = 1;
+		}
+
+		if (r < 0) {
+			crypt_safe_free(CONST_CAST(char*)params->passphrase);
+			params->passphrase = NULL;
+			params->passphrase_size = 0;
+		}
+		check_signal(&r);
+	} while ((r == -EPERM || r == -ERANGE) && (--tries > 0));
+
+	/* Report wrong passphrase if at least one try failed */
+	if (eperm && r == -EPIPE)
+		r = -EPERM;
+
+	return r;
+}
+
+static int action_open_dcryptor(void)
+{
+	struct crypt_device *cd = NULL;
+	struct crypt_params_dcryptor params = {
+		.keyfiles = NULL,
+		.keyfiles_count = 0,
+		.flags = 0,
+		.cipher = ARG_STR(OPT_CIPHER_ID),
+	};
+	const char *activated_name;
+	uint32_t activate_flags = 0;
+	int r;
+
+	activated_name = ARG_SET(OPT_TEST_PASSPHRASE_ID) ? NULL : action_argv[1];
+
+	r = crypt_init_data_device(&cd, ARG_STR(OPT_HEADER_ID) ?: action_argv[0], action_argv[0]);
+	if (r < 0)
+		goto out;
+
+	r = dcryptor_load(cd, &params);
+	if (r < 0)
+		goto out;
+
+	_set_activation_flags(&activate_flags);
+
+	if (activated_name)
+		r = crypt_activate_by_volume_key(cd, activated_name, NULL, 0, activate_flags);
+out:
+	crypt_free(cd);
+	crypt_safe_free(CONST_CAST(char*)params.passphrase);
+	return r;
+}
+
 static int action_open_bitlk(void)
 {
 	struct crypt_device *cd = NULL;
@@ -2399,6 +2466,10 @@ static int action_open(void)
 		if (action_argc < 2 && !ARG_SET(OPT_TEST_PASSPHRASE_ID))
 			goto out;
 		return action_open_tcrypt();
+	} else if (!strcmp(device_type, "dcryptor")) {
+		if (action_argc < 2 && !ARG_SET(OPT_TEST_PASSPHRASE_ID))
+			goto out;
+		return action_open_dcryptor();
 	} else if (!strcmp(device_type, "bitlk")) {
 		if (action_argc < 2 && !ARG_SET(OPT_TEST_PASSPHRASE_ID))
 			goto out;
diff --git a/tests/diskcryptor/password.txt b/tests/diskcryptor/password.txt
new file mode 100644
index 00000000..00dedf6b
--- /dev/null
+++ b/tests/diskcryptor/password.txt
@@ -0,0 +1 @@
+abcde
diff --git a/tests/diskcryptor/volume_aes.bin b/tests/diskcryptor/volume_aes.bin
new file mode 100755
index 00000000..c2d055e8
Binary files /dev/null and b/tests/diskcryptor/volume_aes.bin differ
diff --git a/tests/diskcryptor/volume_aes_twofish.bin b/tests/diskcryptor/volume_aes_twofish.bin
new file mode 100755
index 00000000..c3e016c6
Binary files /dev/null and b/tests/diskcryptor/volume_aes_twofish.bin differ
diff --git a/tests/diskcryptor/volume_aes_twofish_serpent.bin b/tests/diskcryptor/volume_aes_twofish_serpent.bin
new file mode 100755
index 00000000..e3bc9252
Binary files /dev/null and b/tests/diskcryptor/volume_aes_twofish_serpent.bin differ
diff --git a/tests/diskcryptor/volume_serpent.bin b/tests/diskcryptor/volume_serpent.bin
new file mode 100755
index 00000000..6b5fd368
Binary files /dev/null and b/tests/diskcryptor/volume_serpent.bin differ
diff --git a/tests/diskcryptor/volume_serpent_aes.bin b/tests/diskcryptor/volume_serpent_aes.bin
new file mode 100755
index 00000000..f05f570d
Binary files /dev/null and b/tests/diskcryptor/volume_serpent_aes.bin differ
diff --git a/tests/diskcryptor/volume_twofish.bin b/tests/diskcryptor/volume_twofish.bin
new file mode 100755
index 00000000..6dfb7952
Binary files /dev/null and b/tests/diskcryptor/volume_twofish.bin differ
diff --git a/tests/diskcryptor/volume_twofish_serpent.bin b/tests/diskcryptor/volume_twofish_serpent.bin
new file mode 100755
index 00000000..704ae1c4
Binary files /dev/null and b/tests/diskcryptor/volume_twofish_serpent.bin differ
-- 
2.25.1

_______________________________________________
dm-crypt mailing list -- dm-crypt@xxxxxxxx
To unsubscribe send an email to dm-crypt-leave@xxxxxxxx




[Index of Archives]     [Device Mapper Devel]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]     [Fedora Docs]

  Powered by Linux