Move the LUKSv1-specific unlock logic from luks_unlock() into a new unlock_luks1() function, lining up with the structure used for LUKSv2. Also update unlock_luks1() to use a local key_size variable and only set the output parameter on success. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- drivers/block/luks.c | 153 ++++++++++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 51 deletions(-) diff --git a/drivers/block/luks.c b/drivers/block/luks.c index c23b6f50671..a3c86c5a197 100644 --- a/drivers/block/luks.c +++ b/drivers/block/luks.c @@ -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) -- 2.43.0