@@ -323,6 +323,23 @@ static int derive_key_pbkdf2(struct luks1_keyslot *slot, const u8 *pass,
return 0;
}
+/**
+ * unlock_luks1() - Unlock a LUKSv1 partition
+ *
+ * @blk: Block device
+ * @pinfo: Partition information
+ * @hdr: LUKS1 header (already read)
+ * @pass: Passphrase
+ * @pass_len: Length of passphrase
+ * @master_key: Buffer to receive master key
+ * @key_size: Output for key size
+ *
+ * Return: 0 on success, -ve on error
+ */
+static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo,
+ struct luks1_phdr *hdr, const u8 *pass, size_t pass_len,
+ u8 *master_key, u32 *key_size);
+
/**
* try_keyslot() - Try to unlock a LUKS key slot with a derived key
*
@@ -426,62 +443,44 @@ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo,
return -EACCES;
}
-int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
- const u8 *pass, size_t pass_len, u8 *master_key,
- u32 *key_size)
+/**
+ * unlock_luks1() - Unlock a LUKSv1 partition
+ *
+ * Attempts to unlock a LUKSv1 encrypted partition by trying each active
+ * key slot with the provided passphrase. Uses PBKDF2 for key derivation
+ * and supports CBC cipher mode with optional ESSIV.
+ *
+ * @blk: Block device containing the partition
+ * @pinfo: Partition information
+ * @hdr: LUKSv1 header (already read and validated)
+ * @pass: Passphrase (binary data)
+ * @pass_len: Length of passphrase in bytes
+ * @master_key: Buffer to receive unlocked master key (min 128 bytes)
+ * @key_sizep: Output for master key size in bytes (set only on success)
+ *
+ * Return: 0 on success, -ve on error
+ */
+static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo,
+ struct luks1_phdr *hdr, const u8 *pass, size_t pass_len,
+ u8 *master_key, u32 *key_sizep)
{
- uint version, split_key_size, km_blocks, hdr_blocks;
+ uint split_key_size, km_blocks, key_size;
u8 *split_key, *derived_key;
struct hash_algo *hash_algo;
u8 candidate_key[128], *km;
mbedtls_md_type_t md_type;
- struct luks1_phdr *hdr;
struct blk_desc *desc;
int i, ret;
- if (!blk || !pinfo || !pass || !master_key || !key_size)
- return -EINVAL;
-
desc = dev_get_uclass_plat(blk);
- /* LUKS1 header is 592 bytes, calculate blocks needed */
- hdr_blocks = (sizeof(struct luks1_phdr) + desc->blksz - 1) /
- desc->blksz;
-
- /* Allocate buffer for LUKS header */
- ALLOC_CACHE_ALIGN_BUFFER(u8, buffer, hdr_blocks * desc->blksz);
-
- /* Read LUKS header */
- if (blk_read(blk, pinfo->start, hdr_blocks, buffer) != hdr_blocks) {
- log_debug("failed to read LUKS header\n");
- return -EIO;
- }
-
- /* Verify it's LUKS */
- if (memcmp(buffer, LUKS_MAGIC, LUKS_MAGIC_LEN) != 0) {
- log_debug("not a LUKS partition\n");
- return -ENOENT;
- }
-
- version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN));
- if (version == LUKS_VERSION_2)
- return unlock_luks2(blk, pinfo, pass, pass_len, master_key,
- key_size);
-
- if (version != LUKS_VERSION_1) {
- log_debug("unsupported LUKS version %d\n", version);
- return -ENOTSUPP;
- }
-
- hdr = (struct luks1_phdr *)buffer;
-
/* Debug: show what we read from header */
log_debug("Read header at sector %llu, mk_digest[0-7] ",
(unsigned long long)pinfo->start);
log_debug_hex("", (u8 *)hdr->mk_digest, 8);
/* Verify cipher mode - only CBC supported */
- if (strncmp(hdr->cipher_mode, "cbc", 3) != 0) {
+ if (strncmp(hdr->cipher_mode, "cbc", 3)) {
log_debug("only CBC mode is currently supported (got: %.32s)\n",
hdr->cipher_mode);
return -ENOTSUPP;
@@ -495,11 +494,11 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
}
md_type = hash_mbedtls_type(hash_algo);
-
- *key_size = be32_to_cpu(hdr->key_bytes);
+ key_size = be32_to_cpu(hdr->key_bytes);
/* Find the first active slot to get the stripes value */
u32 stripes = 0;
+
for (i = 0; i < LUKS_NUMKEYS; i++) {
if (be32_to_cpu(hdr->key_slot[i].active) == LUKS_KEY_ENABLED) {
stripes = be32_to_cpu(hdr->key_slot[i].stripes);
@@ -511,13 +510,11 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
return -ENOENT;
}
- split_key_size = *key_size * stripes;
-
- log_debug("Trying to unlock LUKS partition: key size: %u bytes\n",
- *key_size);
+ split_key_size = key_size * stripes;
+ log_debug("Unlocking LUKS partition: key size: %u bytes\n", key_size);
/* Allocate buffers */
- derived_key = malloc(*key_size);
+ derived_key = malloc(key_size);
split_key = malloc(split_key_size);
km_blocks = (split_key_size + desc->blksz - 1) / desc->blksz;
km = malloc_cache_aligned(km_blocks * desc->blksz);
@@ -537,18 +534,19 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
/* Derive key for this slot */
ret = derive_key_pbkdf2(slot, pass, pass_len, md_type,
- *key_size, derived_key);
+ key_size, derived_key);
if (ret)
continue;
/* Try to unlock with the derived key */
- ret = try_keyslot(blk, pinfo, hdr, i, md_type, *key_size,
+ ret = try_keyslot(blk, pinfo, hdr, i, md_type, key_size,
derived_key, km, km_blocks, split_key,
candidate_key);
if (!ret) {
/* Successfully unlocked */
- memcpy(master_key, candidate_key, *key_size);
+ memcpy(master_key, candidate_key, key_size);
+ *key_sizep = key_size;
goto out;
}
/* Continue trying other slots on failure */
@@ -559,7 +557,7 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
out:
if (derived_key) {
- memset(derived_key, '\0', *key_size);
+ memset(derived_key, '\0', key_size);
free(derived_key);
}
if (split_key) {
@@ -575,6 +573,59 @@ out:
return ret;
}
+int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
+ const u8 *pass, size_t pass_len, u8 *master_key, u32 *key_sizep)
+{
+ uint version, hdr_blocks;
+ struct luks1_phdr *hdr;
+ struct blk_desc *desc;
+ int ret;
+
+ if (!blk || !pinfo || !pass || !master_key || !key_sizep)
+ return -EINVAL;
+
+ desc = dev_get_uclass_plat(blk);
+
+ /* LUKS1 header is 592 bytes, calculate blocks needed */
+ hdr_blocks = (sizeof(struct luks1_phdr) + desc->blksz - 1) /
+ desc->blksz;
+
+ /* Allocate buffer for LUKS header */
+ ALLOC_CACHE_ALIGN_BUFFER(u8, buffer, hdr_blocks * desc->blksz);
+
+ /* Read LUKS header */
+ if (blk_read(blk, pinfo->start, hdr_blocks, buffer) != hdr_blocks) {
+ log_debug("failed to read LUKS header\n");
+ return -EIO;
+ }
+
+ /* Verify it's LUKS */
+ if (memcmp(buffer, LUKS_MAGIC, LUKS_MAGIC_LEN) != 0) {
+ log_debug("not a LUKS partition\n");
+ return -ENOENT;
+ }
+
+ version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN));
+ switch (version) {
+ case LUKS_VERSION_1:
+ hdr = (struct luks1_phdr *)buffer;
+ ret = unlock_luks1(blk, pinfo, hdr, pass, pass_len, master_key,
+ key_sizep);
+ break;
+ case LUKS_VERSION_2:
+ ret = unlock_luks2(blk, pinfo, pass, pass_len, master_key,
+ key_sizep);
+ break;
+ default:
+ log_debug("unsupported LUKS version %d\n", version);
+ return -ENOTSUPP;
+ }
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo,
const u8 *master_key, u32 key_size, const char *label,
struct udevice **blkmapp)