[Concept,19/24] luks: Create a disk image with LUKS2 encryption

Message ID 20251031065439.3251464-20-sjg@u-boot.org
State New
Headers
Series luks: Provide basic support for unlocking a LUKS1 partition |

Commit Message

Simon Glass Oct. 31, 2025, 6:54 a.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add a new mmc12 image which has a LUKS2-encrypted ext4 partition.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/sandbox/dts/test.dts  |  8 ++++++
 test/py/img/common.py      |  7 ++---
 test/py/img/ubuntu.py      |  4 +--
 test/py/tests/fs_helper.py | 53 +++++++++++++++++++++++++++-----------
 test/py/tests/test_ut.py   |  3 ++-
 5 files changed, 54 insertions(+), 21 deletions(-)
  

Patch

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 9b0a5736cf8..1d0ebc33387 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -49,6 +49,7 @@ 
 		mmc9 = "/mmc9";
 		mmc10 = "/mmc10";
 		mmc11 = "/mmc11";
+		mmc12 = "/mmc12";
 		pci0 = &pci0;
 		pci1 = &pci1;
 		pci2 = &pci2;
@@ -1207,6 +1208,13 @@ 
 		filename = "mmc11.img";
 	};
 
+	/* This is used for LUKS version 2 tests */
+	mmc12 {
+		status = "disabled";
+		compatible = "sandbox,mmc";
+		filename = "mmc12.img";
+	};
+
 	pch {
 		compatible = "sandbox,pch";
 	};
diff --git a/test/py/img/common.py b/test/py/img/common.py
index 01745ce73b3..3b3fdb2734b 100644
--- a/test/py/img/common.py
+++ b/test/py/img/common.py
@@ -33,7 +33,7 @@  def copy_partition(ubman, fsfile, outname):
 
 
 def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir,
-                         script, part2_size=1, use_fde=False):
+                         script, part2_size=1, use_fde=0):
     """Create a 20MB disk image with a single FAT partition
 
     Args:
@@ -46,7 +46,7 @@  def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir,
         dtbdir (str or None): Devicetree filename
         script (str): Script to place in the extlinux.conf file
         part2_size (int): Size of second partition in MB (default: 1)
-        use_fde (bool): True to encrypt the ext4 partition with LUKS1
+        use_fde (int): LUKS version for full-disk encryption (0=none, 1=LUKS1, 2=LUKS2)
     """
     fsh = FsHelper(config, 'vfat', 18, prefix=basename)
     fsh.setup()
@@ -82,7 +82,8 @@  def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir,
 
     ext4 = FsHelper(config, 'ext4', max(1, part2_size - 30), prefix=basename,
                     part_mb=part2_size,
-                    encrypt_passphrase='test' if use_fde else None)
+                    encrypt_passphrase='test' if use_fde else None,
+                    luks_version=use_fde if use_fde else 2)
     ext4.setup()
 
     bindir = os.path.join(ext4.srcdir, 'bin')
diff --git a/test/py/img/ubuntu.py b/test/py/img/ubuntu.py
index 58ee9f20277..b783f7eb3cf 100644
--- a/test/py/img/ubuntu.py
+++ b/test/py/img/ubuntu.py
@@ -7,7 +7,7 @@  from img.common import setup_extlinux_image
 
 
 def setup_ubuntu_image(config, log, devnum, basename, version='24.04.1 LTS',
-                       use_fde=False):
+                       use_fde=0):
     """Create a Ubuntu disk image with a FAT partition and ext4 partition
 
     This creates a FAT partition containing extlinux files, kernel, etc. and a
@@ -18,7 +18,7 @@  def setup_ubuntu_image(config, log, devnum, basename, version='24.04.1 LTS',
         log (multiplexed_log.Logfile): Log to write to
         devnum (int): Device number to use, e.g. 1
         basename (str): Base name to use in the filename, e.g. 'mmc'
-        use_fde (bool): True to set up full-disk encryption
+        use_fde (int): LUKS version for full-disk encryption (0=none, 1=LUKS1, 2=LUKS2)
     """
     vmlinux = 'vmlinuz-6.8.0-53-generic'
     initrd = 'initrd.img-6.8.0-53-generic'
diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py
index 49747be1788..914de09e381 100644
--- a/test/py/tests/fs_helper.py
+++ b/test/py/tests/fs_helper.py
@@ -38,12 +38,20 @@  class FsHelper:
                 fsh.mk_fs()
                 ...
 
-        To create an encrypted LUKS1 partition:
+        To create an encrypted LUKS2 partition (default):
 
             with FsHelper(ubman.config, 'ext4', 10, 'mmc1',
                           encrypt_passphrase='test') as fsh:
                 # create files in the fsh.srcdir directory
-                fsh.mk_fs()  # Creates and encrypts the filesystem
+                fsh.mk_fs()  # Creates and encrypts the filesystem with LUKS2
+                ...
+
+        To create an encrypted LUKS1 partition:
+
+            with FsHelper(ubman.config, 'ext4', 10, 'mmc1',
+                          encrypt_passphrase='test', luks_version=1) as fsh:
+                # create files in the fsh.srcdir directory
+                fsh.mk_fs()  # Creates and encrypts the filesystem with LUKS1
                 ...
 
     Properties:
@@ -51,7 +59,7 @@  class FsHelper:
             default value but can be overwritten
     """
     def __init__(self, config, fs_type, size_mb, prefix, part_mb=None,
-                 encrypt_passphrase=None):
+                 encrypt_passphrase=None, luks_version=2):
         """Set up a new object
 
         Args:
@@ -64,7 +72,8 @@  class FsHelper:
                 to size_mb. This can be used to make the partition larger than
                 the filesystem, to create space for disk-encryption metadata
             encrypt_passphrase (str, optional): If provided, encrypt the
-                filesystem with LUKS1 using this passphrase
+                filesystem with LUKS using this passphrase
+            luks_version (int): LUKS version to use (1 or 2). Defaults to 2.
         """
         if ('fat' not in fs_type and 'ext' not in fs_type and
              fs_type not in ['exfat', 'fs_generic']):
@@ -77,6 +86,7 @@  class FsHelper:
         self.prefix = prefix
         self.quiet = True
         self.encrypt_passphrase = encrypt_passphrase
+        self.luks_version = luks_version
 
         # Use a default filename; the caller can adjust it
         leaf = f'{prefix}.{fs_type}.img'
@@ -166,11 +176,10 @@  class FsHelper:
                 self.srcdir = self.tmpdir.name
 
     def encrypt_luks(self, passphrase):
-        """Encrypt the filesystem image with LUKS1
+        """Encrypt the filesystem image with LUKS
 
-        This replaces the filesystem image with a LUKS1-encrypted version.
-        LUKS1 is used because U-Boot's unlock implementation currently only
-        supports LUKS version 1.
+        This replaces the filesystem image with a LUKS-encrypted version.
+        The LUKS version is determined by self.luks_version.
 
         Args:
             passphrase (str): Passphrase for the LUKS container
@@ -180,11 +189,25 @@  class FsHelper:
 
         Raises:
             CalledProcessError: If cryptsetup is not available or fails
+            ValueError: If an unsupported LUKS version is specified
         """
-        # LUKS1 encryption parameters
-        cipher = 'aes-cbc-essiv:sha256'
-        key_size = 256
-        hash_alg = 'sha256'
+        # LUKS encryption parameters
+        if self.luks_version == 1:
+            # LUKS1 parameters
+            cipher = 'aes-cbc-essiv:sha256'
+            key_size = 256
+            hash_alg = 'sha256'
+            luks_type = 'luks1'
+        elif self.luks_version == 2:
+            # LUKS2 parameters (modern defaults)
+            cipher = 'aes-xts-plain64'
+            key_size = 512  # XTS uses 512-bit keys (2x256)
+            hash_alg = 'sha256'
+            luks_type = 'luks2'
+        else:
+            raise ValueError(f"Unsupported LUKS version: {self.luks_version}")
+
+        key_size_str = str(key_size)
 
         # Save the original filesystem image
         orig_fs_img = f'{self.fs_img}.orig'
@@ -214,11 +237,11 @@  class FsHelper:
             stdout=DEVNULL, stderr=DEVNULL, check=False)
 
         try:
-            # Format as LUKS1
+            # Format as LUKS (version determined by luks_type)
             run(['cryptsetup', 'luksFormat',
-                 '--type', 'luks1',
+                 '--type', luks_type,
                  '--cipher', cipher,
-                 '--key-size', str(key_size),
+                 '--key-size', key_size_str,
                  '--hash', hash_alg,
                  '--iter-time', '10',  # Very fast for testing (low security)
                  luks_img],
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index 218f5a74ac1..94d98b3b73b 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -83,7 +83,8 @@  def test_ut_dm_init_bootstd(u_boot_config, u_boot_log):
     setup_ubuntu_image(u_boot_config, u_boot_log, 3, 'flash', '25.04')
     setup_localboot_image(u_boot_config, u_boot_log)
     setup_vbe_image(u_boot_config, u_boot_log)
-    setup_ubuntu_image(u_boot_config, u_boot_log, 11, 'mmc', use_fde=True)
+    setup_ubuntu_image(u_boot_config, u_boot_log, 11, 'mmc', use_fde=1)
+    setup_ubuntu_image(u_boot_config, u_boot_log, 12, 'mmc', use_fde=2)
 
 def test_ut(ubman, ut_subtest):
     """Execute a "ut" subtest.