From: Kfir Kahanov <kfirka3@gmail.com>
To: cryptsetup@lists.linux.dev
Cc: Kfir Kahanov <kfirka3@gmail.com>
Subject: [PATCH 2/2] bitlocker: Add clearkey option
Date: Sat, 4 Oct 2025 03:35:54 +0300 [thread overview]
Message-ID: <20251004003554.234647-3-kfirka3@gmail.com> (raw)
In-Reply-To: <20251004003554.234647-1-kfirka3@gmail.com>
In order to bypass getting the password.
---
lib/keyslot_context.c | 97 +++++++++++++++++++++++++++++++++++++++
lib/keyslot_context.h | 2 +
lib/libcryptsetup.h | 24 ++++++++++
lib/libcryptsetup.sym | 1 +
lib/setup.c | 24 +++++++++-
src/cryptsetup.c | 20 +++++---
src/cryptsetup_arg_list.h | 2 +
src/cryptsetup_args.h | 1 +
src/utils_arg_names.h | 1 +
9 files changed, 165 insertions(+), 7 deletions(-)
diff --git a/lib/keyslot_context.c b/lib/keyslot_context.c
index 1b137823..a6df53fb 100644
--- a/lib/keyslot_context.c
+++ b/lib/keyslot_context.c
@@ -304,6 +304,68 @@ static int get_fvault2_volume_key_by_key(struct crypt_device *cd,
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
+/* Clearkey-specific functions */
+static int get_luks1_volume_key_by_clearkey(struct crypt_device *cd __attribute__((unused)),
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ int keyslot __attribute__((unused)),
+ struct volume_key **r_vk __attribute__((unused)))
+{
+ /* LUKS1 does not support clearkey protection */
+ return -ENOTSUP;
+}
+
+static int get_luks2_volume_key_by_clearkey(struct crypt_device *cd __attribute__((unused)),
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ int keyslot __attribute__((unused)),
+ struct volume_key **r_vk __attribute__((unused)))
+{
+ /* LUKS2 does not support clearkey protection */
+ return -ENOTSUP;
+}
+
+static int get_plain_volume_key_by_clearkey(struct crypt_device *cd __attribute__((unused)),
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ struct volume_key **r_vk __attribute__((unused)))
+{
+ /* Plain does not support clearkey protection */
+ return -ENOTSUP;
+}
+
+static int get_bitlk_volume_key_by_clearkey(struct crypt_device *cd,
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ const struct bitlk_metadata *params,
+ struct volume_key **r_vk)
+{
+ /* For BitLocker clearkey, call BITLK_get_volume_key without passphrase */
+ return BITLK_get_volume_key(cd, NULL, 0, params, r_vk);
+}
+
+static int get_fvault2_volume_key_by_clearkey(struct crypt_device *cd __attribute__((unused)),
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ const struct fvault2_params *params __attribute__((unused)),
+ struct volume_key **r_vk __attribute__((unused)))
+{
+ /* FVAULT2 does not support clearkey protection */
+ return -ENOTSUP;
+}
+
+static int get_verity_volume_key_by_clearkey(struct crypt_device *cd __attribute__((unused)),
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ struct volume_key **r_vk __attribute__((unused)),
+ struct volume_key **r_signature __attribute__((unused)))
+{
+ /* Verity does not support clearkey protection */
+ return -ENOTSUP;
+}
+
+static int get_integrity_volume_key_by_clearkey(struct crypt_device *cd __attribute__((unused)),
+ struct crypt_keyslot_context *kc __attribute__((unused)),
+ struct volume_key **r_vk __attribute__((unused)))
+{
+ /* Integrity does not support clearkey protection */
+ return -ENOTSUP;
+}
+
static int get_generic_signed_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
struct volume_key **r_vk,
@@ -629,6 +691,26 @@ void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc
crypt_keyslot_context_init_common(kc);
}
+void crypt_keyslot_context_init_by_clearkey_internal(struct crypt_keyslot_context *kc)
+{
+ assert(kc);
+
+ kc->type = CRYPT_KC_TYPE_KEY;
+
+ kc->get_luks1_volume_key = get_luks1_volume_key_by_clearkey;
+ kc->get_luks2_volume_key = get_luks2_volume_key_by_clearkey;
+ kc->get_plain_volume_key = get_plain_volume_key_by_clearkey;
+ kc->get_bitlk_volume_key = get_bitlk_volume_key_by_clearkey;
+ kc->get_fvault2_volume_key = get_fvault2_volume_key_by_clearkey;
+ kc->get_verity_volume_key = get_verity_volume_key_by_clearkey;
+ kc->get_integrity_volume_key = get_integrity_volume_key_by_clearkey;
+
+ kc->get_key_size = key_get_key_size;
+ kc->context_free = key_context_free;
+ crypt_keyslot_context_init_common(kc);
+}
+
+
static void signed_key_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_SIGNED_KEY);
@@ -1196,6 +1278,21 @@ CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_vk_in_keyring, 2, 7,
return _crypt_keyslot_context_init_by_vk_in_keyring(key_description, kc, false);
}
+CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_clearkey, 2, 8, struct crypt_device *cd,
+ struct crypt_keyslot_context **kc)
+{
+ if (!kc)
+ return -EINVAL;
+
+ *kc = crypt_zalloc(sizeof(**kc));
+ if (!*kc)
+ return -ENOMEM;
+
+ crypt_keyslot_context_init_by_clearkey_internal(*kc);
+
+ return 0;
+}
+
int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc)
{
return kc ? kc->error : -EINVAL;
diff --git a/lib/keyslot_context.h b/lib/keyslot_context.h
index a2e42b20..f373bf8d 100644
--- a/lib/keyslot_context.h
+++ b/lib/keyslot_context.h
@@ -175,6 +175,8 @@ void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *
void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description);
+void crypt_keyslot_context_init_by_clearkey_internal(struct crypt_keyslot_context *kc);
+
const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc);
#endif /* KEYSLOT_CONTEXT_H */
diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h
index 77eb29ef..07b18f70 100644
--- a/lib/libcryptsetup.h
+++ b/lib/libcryptsetup.h
@@ -1352,6 +1352,17 @@ int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd,
const char *key_description,
struct crypt_keyslot_context **kc);
+/**
+ * Initialize keyslot context for clear key.
+ *
+ * @param cd crypt device handle initialized to LUKS device context
+ * @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_KEY
+ *
+ * @return zero on success or negative errno otherwise.
+ */
+int crypt_keyslot_context_init_by_clearkey(struct crypt_device *cd,
+ struct crypt_keyslot_context **kc);
+
/**
* Get error code per keyslot context from last failed call.
*
@@ -1823,6 +1834,19 @@ int crypt_activate_by_keyring(struct crypt_device *cd,
int keyslot,
uint32_t flags);
+/**
+ * Activate BITLK device using clearkey.
+ *
+ * @param cd crypt device handle
+ * @param name name of device to create
+ * @param flags activation flags
+ *
+ * @return @e 0 on success or negative errno value otherwise.
+ */
+int crypt_activate_by_clearkey(struct crypt_device *cd,
+ const char *name,
+ uint32_t flags);
+
/** lazy deactivation - remove once last user releases it */
#define CRYPT_DEACTIVATE_DEFERRED (UINT32_C(1) << 0)
/** force deactivation - if the device is busy, it is replaced by error device */
diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym
index 3a54431a..f6463af2 100644
--- a/lib/libcryptsetup.sym
+++ b/lib/libcryptsetup.sym
@@ -61,6 +61,7 @@ CRYPTSETUP_2.0 {
crypt_activate_by_volume_key;
crypt_activate_by_signed_key;
crypt_activate_by_keyring;
+ crypt_activate_by_clearkey;
crypt_deactivate;
crypt_deactivate_by_name;
crypt_volume_key_get;
diff --git a/lib/setup.c b/lib/setup.c
index 37e6f7d9..1be05cfe 100644
--- a/lib/setup.c
+++ b/lib/setup.c
@@ -5707,6 +5707,20 @@ int crypt_activate_by_signed_key(struct crypt_device *cd,
return r;
}
+int crypt_activate_by_clearkey(struct crypt_device *cd,
+ const char *name,
+ uint32_t flags)
+{
+ int r;
+ struct crypt_keyslot_context kc = {};
+
+ crypt_keyslot_context_init_by_clearkey_internal(&kc);
+ r = crypt_activate_by_keyslot_context(cd, name, CRYPT_ANY_SLOT /* unused */, &kc, CRYPT_ANY_SLOT, &kc, flags);
+ crypt_keyslot_context_destroy_internal(&kc);
+
+ return r;
+}
+
int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags)
{
struct crypt_device *fake_cd = NULL;
@@ -5917,7 +5931,7 @@ int crypt_volume_key_get_by_keyslot_context(struct crypt_device *cd,
struct volume_key *vk = NULL;
if (!cd || !volume_key || !volume_key_size ||
- (!kc && !isLUKS(cd->type) && !isTCRYPT(cd->type) && !isVERITY(cd->type)))
+ (!kc && !isLUKS(cd->type) && !isTCRYPT(cd->type) && !isVERITY(cd->type) && !isBITLK(cd->type)))
return -EINVAL;
if (isLUKS2(cd->type) && keyslot != CRYPT_ANY_SLOT)
@@ -5977,6 +5991,14 @@ int crypt_volume_key_get_by_keyslot_context(struct crypt_device *cd,
} else if (isBITLK(cd->type)) {
if (kc && kc->get_bitlk_volume_key)
r = kc->get_bitlk_volume_key(cd, kc, &cd->u.bitlk.params, &vk);
+ else if (!kc) {
+ struct crypt_keyslot_context *kc_clearkey = NULL;
+ r = crypt_keyslot_context_init_by_clearkey(cd, &kc_clearkey);
+ if (r >= 0) {
+ r = kc_clearkey->get_bitlk_volume_key(cd, kc_clearkey, &cd->u.bitlk.params, &vk);
+ }
+ crypt_keyslot_context_free(kc_clearkey);
+ }
if (r < 0)
log_err(cd, _("Cannot retrieve volume key for BITLK device."));
} else if (isFVAULT2(cd->type)) {
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index bd2ee780..134162c6 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -508,6 +508,11 @@ static int action_open_bitlk(void)
goto out;
r = crypt_activate_by_volume_key(cd, activated_name,
key, keysize, activate_flags);
+ } else if (ARG_SET(OPT_CLEARKEY_ID)) {
+ /* For clearkey, we don't need a passphrase - pass NULL to activate_by_passphrase */
+ r = crypt_activate_by_clearkey(cd, activated_name, activate_flags);
+ if (r < 0)
+ log_err(_("No clearkey protection found on BITLK device."));
} else {
tries = set_tries_tty(false);
do {
@@ -617,14 +622,17 @@ static int bitlkDump_with_volume_key(struct crypt_device *cd)
if (!vk)
return -ENOMEM;
- r = tools_get_key(NULL, &password, &passwordLen,
- ARG_UINT64(OPT_KEYFILE_OFFSET_ID), ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID),
- ARG_UINT32(OPT_TIMEOUT_ID), 0, 0, cd);
- if (r < 0)
- goto out;
+ if (!ARG_SET(OPT_CLEARKEY_ID)) {
+ r = tools_get_key(NULL, &password, &passwordLen,
+ ARG_UINT64(OPT_KEYFILE_OFFSET_ID), ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID),
+ ARG_UINT32(OPT_TIMEOUT_ID), 0, 0, cd);
+ if (r < 0)
+ goto out;
+ }
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, vk, &vk_size,
- password, passwordLen);
+ password, passwordLen);
+
tools_passphrase_msg(r);
check_signal(&r);
if (r < 0)
diff --git a/src/cryptsetup_arg_list.h b/src/cryptsetup_arg_list.h
index 26652dd8..95b2c991 100644
--- a/src/cryptsetup_arg_list.h
+++ b/src/cryptsetup_arg_list.h
@@ -241,6 +241,8 @@ ARG(OPT_USE_DIRECTIO, '\0', POPT_ARG_NONE, N_("Use direct-io when accessing devi
ARG(OPT_USE_FSYNC, '\0', POPT_ARG_NONE, N_("Use fsync after each block"), NULL, CRYPT_ARG_BOOL, {}, {})
ARG(OPT_WRITE_LOG, '\0', POPT_ARG_NONE, N_("Update log file after every block"), NULL, CRYPT_ARG_BOOL, {}, {})
+
+ARG(OPT_CLEARKEY, '\0', POPT_ARG_NONE, N_("Open BITLK device using only clearkey protection"), NULL, CRYPT_ARG_BOOL, {}, {})
/* aliases */
diff --git a/src/cryptsetup_args.h b/src/cryptsetup_args.h
index 43926f99..3ef58b61 100644
--- a/src/cryptsetup_args.h
+++ b/src/cryptsetup_args.h
@@ -43,6 +43,7 @@
/* avoid unshielded commas in ARG() macros later */
#define OPT_ALIGN_PAYLOAD_ACTIONS { FORMAT_ACTION, REENCRYPT_ACTION }
#define OPT_ALLOW_DISCARDS_ACTIONS { OPEN_ACTION }
+#define OPT_CLEARKEY_ACTIONS { OPEN_ACTION, BITLKDUMP_ACTION }
#define OPT_DEFERRED_ACTIONS { CLOSE_ACTION }
#define OPT_DEVICE_SIZE_ACTIONS { OPEN_ACTION, RESIZE_ACTION, REENCRYPT_ACTION }
#define OPT_DISABLE_BLKID_ACTIONS { FORMAT_ACTION, REENCRYPT_ACTION }
diff --git a/src/utils_arg_names.h b/src/utils_arg_names.h
index a01419d3..f50c26dc 100644
--- a/src/utils_arg_names.h
+++ b/src/utils_arg_names.h
@@ -20,6 +20,7 @@
#define OPT_CANCEL_DEFERRED "cancel-deferred"
#define OPT_CHECK_AT_MOST_ONCE "check-at-most-once"
#define OPT_CIPHER "cipher"
+#define OPT_CLEARKEY "clearkey"
#define OPT_DATA_BLOCK_SIZE "data-block-size"
#define OPT_DATA_BLOCKS "data-blocks"
#define OPT_DATA_DEVICE "data-device"
--
2.43.0
next prev parent reply other threads:[~2025-10-04 0:36 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-04 0:35 [PATCH 0/2] Bitlocker: Support clearkey Kfir Kahanov
2025-10-04 0:35 ` [PATCH 1/2] bitlocker: " Kfir Kahanov
2025-10-04 0:35 ` Kfir Kahanov [this message]
2025-10-04 18:17 ` [PATCH 0/2] Bitlocker: " Milan Broz
2025-10-04 19:28 ` Kfir Ka
2025-10-04 19:46 ` Milan Broz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251004003554.234647-3-kfirka3@gmail.com \
--to=kfirka3@gmail.com \
--cc=cryptsetup@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox