diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py index 360cbfd16a..b74182625a 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -280,11 +280,13 @@ def encrypt( enc_password: Password | None, lock_after_create: bool = True, iter_time: int = DEFAULT_ITER_TIME, + cipher: str | None = None, ) -> Luks2: luks_handler = Luks2( dev_path, mapper_name=mapper_name, password=enc_password, + cipher=cipher, ) key_file = luks_handler.encrypt(iter_time=iter_time) @@ -316,6 +318,7 @@ def format_encrypted( dev_path, mapper_name=mapper_name, password=enc_conf.encryption_password, + cipher=enc_conf.cipher, ) key_file = luks_handler.encrypt(iter_time=enc_conf.iter_time) diff --git a/archinstall/lib/disk/encryption_menu.py b/archinstall/lib/disk/encryption_menu.py index 53aa73fe37..a1811df871 100644 --- a/archinstall/lib/disk/encryption_menu.py +++ b/archinstall/lib/disk/encryption_menu.py @@ -8,6 +8,7 @@ from archinstall.lib.menu.util import get_password from archinstall.lib.models.device import ( DEFAULT_ITER_TIME, + EncryptionCipher, DeviceModification, DiskEncryption, EncryptionType, @@ -47,6 +48,45 @@ def __init__( allow_reset=True, ) + async def _select_cipher(self, current_value: Any) -> Any: + items = [MenuItem(cipher.value, value=cipher) for cipher in EncryptionCipher] + group = MenuItemGroup(items) + + result = await Selection[EncryptionCipher]( + group, + header=tr('Select encryption cipher'), + allow_skip=True, + allow_reset=True, + ).show() + + match result.type_: + case ResultType.Selection: + selected_enum = result.get_value() + self._enc_config.cipher = selected_enum + return selected_enum + case _: + return current_value + + def _prev_cipher(self, item: MenuItem) -> str | None: + val = item.value if item.value else getattr(self._enc_config, 'cipher', None) + + if not val: + val_str = 'aes-xts-plain64' + elif hasattr(val, 'value'): + val_str = val.value + else: + val_str = str(val) + + return f'{tr("Encryption cipher")}: {val_str}' + + match result.type_: + case ResultType.Selection: + selected_value = result.get_value() + self._enc_config.cipher = selected_value + return selected_value + case _: + return current_value + def _define_menu_options(self) -> list[MenuItem]: return [ MenuItem( @@ -72,6 +112,14 @@ def _define_menu_options(self) -> list[MenuItem]: preview_action=self._prev_iter_time, key='iter_time', ), + MenuItem( + text=tr('Encryption cipher'), + action=self._select_cipher, + value=self._enc_config.cipher if hasattr(self._enc_config, 'cipher') and self._enc_config.cipher else EncryptionCipher.AES_XTS_PLAIN64, + preview_action=self._prev_cipher, + dependencies=[self._check_dep_enc_type], + key='cipher', + ), MenuItem( text=tr('Partitions'), action=lambda x: select_partitions_to_encrypt(self._device_modifications, x), @@ -132,6 +180,7 @@ async def show(self) -> DiskEncryption | None: iter_time: int | None = self._item_group.find_by_key('iter_time').value enc_partitions = self._item_group.find_by_key('partitions').value enc_lvm_vols = self._item_group.find_by_key('lvm_volumes').value + cipher_value: str | None = self._item_group.find_by_key('cipher').value assert enc_type is not None assert enc_partitions is not None @@ -151,6 +200,7 @@ async def show(self) -> DiskEncryption | None: lvm_volumes=enc_lvm_vols, hsm_device=enc_config.hsm_device, iter_time=iter_time or DEFAULT_ITER_TIME, + cipher=cipher_value, ) return None diff --git a/archinstall/lib/disk/luks.py b/archinstall/lib/disk/luks.py index 3a3679d0b2..0d06ff3051 100644 --- a/archinstall/lib/disk/luks.py +++ b/archinstall/lib/disk/luks.py @@ -20,6 +20,7 @@ class Luks2: password: Password | None = None key_file: Path | None = None auto_unmount: bool = False + cipher: str | None = None @property def mapper_dev(self) -> Path | None: @@ -94,6 +95,11 @@ def encrypt( str(iter_time), *key_file_arg, '--use-urandom', + ] + if self.cipher: + cmd += ['--cipher', self.cipher] + + cmd += [ 'luksFormat', str(self.luks_dev_path), ] diff --git a/archinstall/lib/models/device.py b/archinstall/lib/models/device.py index a50f7d8e62..15caa55e65 100644 --- a/archinstall/lib/models/device.py +++ b/archinstall/lib/models/device.py @@ -1469,6 +1469,10 @@ class _DiskEncryptionSerialization(TypedDict): hsm_device: NotRequired[_Fido2DeviceSerialization] iter_time: NotRequired[int] +class EncryptionCipher(Enum): + AES_XTS_PLAIN64 = "aes-xts-plain64" + AES_ADIANTUM_PLAIN64 = "aes-adiantum-plain64" + CHACHA20_RANDOM_PLAIN64 = "chacha20-random-plain64" @dataclass class DiskEncryption: @@ -1478,6 +1482,7 @@ class DiskEncryption: lvm_volumes: list[LvmVolume] = field(default_factory=list) hsm_device: Fido2Device | None = None iter_time: int = DEFAULT_ITER_TIME + cipher: EncryptionCipher | None = None def __post_init__(self) -> None: if self.encryption_type in [EncryptionType.LUKS, EncryptionType.LVM_ON_LUKS] and not self.partitions: @@ -1505,6 +1510,9 @@ def json(self) -> _DiskEncryptionSerialization: if self.iter_time != DEFAULT_ITER_TIME: # Only include if not default obj['iter_time'] = self.iter_time + if self.cipher: + obj['cipher'] = self.cipher + return obj @staticmethod