From ed7ba45ae3a8660abc62be651defe2d124f7dc11 Mon Sep 17 00:00:00 2001 From: Alperen42v <243298691+Alperen42v@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:12:59 +0300 Subject: [PATCH] new ciphers --- archinstall/lib/disk/device_handler.py | 5 +-- archinstall/lib/disk/encryption_menu.py | 27 ++++++-------- archinstall/lib/disk/luks.py | 16 +++------ archinstall/lib/models/device.py | 48 ++++++++++++++++++------- 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py index 9bb93821..f208a957 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -23,6 +23,7 @@ from archinstall.lib.models.device import ( BtrfsMountOption, DeviceModification, DiskEncryption, + EncryptionCipher, FilesystemType, LsblkInfo, ModificationStatus, @@ -281,7 +282,7 @@ class DeviceHandler: enc_password: Password | None, lock_after_create: bool = True, iter_time: int = DEFAULT_ITER_TIME, - cipher: str = DEFAULT_CIPHER, + cipher: EncryptionCipher = DEFAULT_CIPHER, ) -> Luks2: luks_handler = Luks2( dev_path, @@ -627,4 +628,4 @@ class DeviceHandler: self._wipe(block_device.device_info.path) -device_handler = DeviceHandler() +device_handler = DeviceHandler() \ No newline at end of file diff --git a/archinstall/lib/disk/encryption_menu.py b/archinstall/lib/disk/encryption_menu.py index 248a055f..124eaccc 100644 --- a/archinstall/lib/disk/encryption_menu.py +++ b/archinstall/lib/disk/encryption_menu.py @@ -11,6 +11,7 @@ from archinstall.lib.models.device import ( DEFAULT_ITER_TIME, DeviceModification, DiskEncryption, + EncryptionCipher, EncryptionType, Fido2Device, LvmConfiguration, @@ -112,7 +113,7 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): return await select_lvm_vols_to_encrypt(self._lvm_config, preset=preset) return [] - async def _select_cipher(self, preset: str | None) -> str | None: + async def _select_cipher(self, preset: EncryptionCipher | None) -> EncryptionCipher | None: return await select_encryption_cipher(preset) def _check_dep_enc_type(self) -> bool: @@ -141,7 +142,7 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value enc_password: Password | None = self._item_group.find_by_key('encryption_password').value - cipher: str | None = self._item_group.find_by_key('cipher').value + cipher: EncryptionCipher | None = self._item_group.find_by_key('cipher').value 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 @@ -214,9 +215,9 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): return None def _prev_cipher(self, item: MenuItem) -> str | None: - cipher = self._item_group.find_by_key('cipher').value + cipher: EncryptionCipher | None = self._item_group.find_by_key('cipher').value if cipher: - return f'{tr("Encryption cipher")}: {cipher}' + return f'{tr("Encryption cipher")}: {cipher.value}' return None def _prev_partitions(self, item: MenuItem) -> str | None: @@ -429,23 +430,17 @@ async def select_iteration_time(preset: int | None = None) -> int | None: return None -async def select_encryption_cipher(preset: str | None = None) -> str | None: - # Regular block-cipher modes: accepted directly by `cryptsetup --cipher`. - options = [ - 'aes-xts-plain64', - 'aes-cbc-essiv:sha256', - 'serpent-xts-plain64', - 'twofish-xts-plain64', - ] +async def select_encryption_cipher(preset: EncryptionCipher | None = None) -> EncryptionCipher | None: + options = list(EncryptionCipher) if not preset: - preset = options[0] + preset = DEFAULT_CIPHER - items = [MenuItem(o, value=o) for o in options] + items = [MenuItem(o.value, value=o) for o in options] group = MenuItemGroup(items) group.set_focus_by_value(preset) - result = await Selection[str]( + result = await Selection[EncryptionCipher]( group, header=tr('Select encryption cipher'), allow_skip=True, @@ -458,4 +453,4 @@ async def select_encryption_cipher(preset: str | None = None) -> str | None: case ResultType.Skip: return preset case ResultType.Selection: - return result.get_value() + return result.get_value() \ No newline at end of file diff --git a/archinstall/lib/disk/luks.py b/archinstall/lib/disk/luks.py index d3d7e707..16325712 100644 --- a/archinstall/lib/disk/luks.py +++ b/archinstall/lib/disk/luks.py @@ -8,7 +8,7 @@ from archinstall.lib.command import SysCommand, SysCommandWorker, run from archinstall.lib.disk.utils import get_lsblk_info, umount from archinstall.lib.exceptions import DiskError, SysCallError from archinstall.lib.log import debug, info -from archinstall.lib.models.device import CIPHER_KEY_SIZES, DEFAULT_CIPHER, DEFAULT_ITER_TIME +from archinstall.lib.models.device import DEFAULT_CIPHER, DEFAULT_ITER_TIME, EncryptionCipher from archinstall.lib.models.users import Password from archinstall.lib.utils.util import generate_password @@ -69,21 +69,15 @@ class Luks2: def encrypt( self, - key_size: int = 512, hash_type: str = 'sha512', iter_time: int = DEFAULT_ITER_TIME, key_file: Path | None = None, - cipher: str = DEFAULT_CIPHER, + cipher: EncryptionCipher = DEFAULT_CIPHER, ) -> Path | None: debug(f'Luks2 encrypting: {self.luks_dev_path}') key_file_arg, passphrase = self._get_passphrase_args(key_file) - # Resolve the correct key size for this cipher. - # XTS mode uses two keys (e.g. 256+256 = 512 bits for aes-xts-plain64), - # CBC mode uses a single key (max 256 bits for aes-cbc-essiv:sha256). - resolved_key_size = CIPHER_KEY_SIZES.get(cipher, key_size) - cmd = [ 'cryptsetup', '--batch-mode', @@ -93,11 +87,11 @@ class Luks2: '--pbkdf', 'argon2id', '--cipher', - cipher, + cipher.value, '--hash', hash_type, '--key-size', - str(resolved_key_size), + str(cipher.key_size), ] cmd += [ @@ -320,4 +314,4 @@ def unlock_luks2_dev( if not luks_handler.is_unlocked(): luks_handler.unlock() - return luks_handler + return luks_handler \ No newline at end of file diff --git a/archinstall/lib/models/device.py b/archinstall/lib/models/device.py index b1ed353e..74d7fb6e 100644 --- a/archinstall/lib/models/device.py +++ b/archinstall/lib/models/device.py @@ -1462,16 +1462,37 @@ class EncryptionType(StrEnum): return type_to_text[self] -DEFAULT_CIPHER = 'aes-xts-plain64' +class EncryptionCipher(Enum): + # None passed to cryptsetup means its built-in default (aes-xts-plain64). + # Adiantum is for CPUs without AES acceleration. It is a composite mode: + # spec must name both the stream cipher and block cipher + # (xchacha12,aes) or the kernel rejects it as unsupported. + AES_XTS_PLAIN64 = 'aes-xts-plain64' + # xchacha12 = faster (Android default), xchacha20 = wider margin. + ADIANTUM_XCHACHA12_PLAIN64 = 'xchacha12,aes-adiantum-plain64' + ADIANTUM_XCHACHA20_PLAIN64 = 'xchacha20,aes-adiantum-plain64' + # AES finalist, conservative margin (32 rounds), bitslices well + # on AVX2 despite no dedicated hw acceleration. + SERPENT_XTS_PLAIN64 = 'serpent-xts-plain64' + # Wide-block AES mode (AES-NI accelerated), single 256-bit key. + AES_HCTR2_PLAIN64 = 'aes-hctr2-plain64' + # Non-NIST standard (ISO/NESSIE/CRYPTREC), AVX2 accelerated. + CAMELLIA_XTS_PLAIN64 = 'camellia-xts-plain64' + # Legacy CBC mode — weaker than XTS against watermarking attacks, + # slower due to per-sector ESSIV/SHA256. Included for compatibility. + AES_CBC_ESSIV_SHA256 = 'aes-cbc-essiv:sha256' + + @property + def key_size(self) -> int: + # XTS uses two keys, so 512 bits => 256-bit cipher. Adiantum + # and HCTR2 use a single 256-bit key; 512 makes cryptsetup fail. + if '-xts-' in self.value: + return 512 + return 256 + + +DEFAULT_CIPHER = EncryptionCipher.AES_XTS_PLAIN64 -# XTS mode splits the key in two halves so needs double the bits. -# CBC/ECB use the key directly — max 256 bit. -CIPHER_KEY_SIZES: dict[str, int] = { - 'aes-xts-plain64': 512, # XTS: 256+256 - 'aes-cbc-essiv:sha256': 256, # CBC: single 256-bit key - 'serpent-xts-plain64': 512, # XTS: 256+256 - 'twofish-xts-plain64': 512, # XTS: 256+256 -} class _DiskEncryptionSerialization(TypedDict): encryption_type: str @@ -1490,7 +1511,7 @@ class DiskEncryption: lvm_volumes: list[LvmVolume] = field(default_factory=list) hsm_device: Fido2Device | None = None iter_time: int = DEFAULT_ITER_TIME - cipher: str = DEFAULT_CIPHER + cipher: EncryptionCipher = DEFAULT_CIPHER def __post_init__(self) -> None: if self.encryption_type in [EncryptionType.LUKS, EncryptionType.LVM_ON_LUKS] and not self.partitions: @@ -1519,7 +1540,7 @@ class DiskEncryption: obj['iter_time'] = self.iter_time if self.cipher != DEFAULT_CIPHER: # Only include if not default - obj['cipher'] = self.cipher + obj['cipher'] = self.cipher.value return obj @@ -1565,7 +1586,8 @@ class DiskEncryption: if vol.obj_id in disk_encryption.get('lvm_volumes', []): volumes.append(vol) - cipher = disk_encryption.get('cipher', None) or DEFAULT_CIPHER + cipher_str = disk_encryption.get('cipher', None) + cipher = EncryptionCipher(cipher_str) if cipher_str else DEFAULT_CIPHER enc = cls( EncryptionType(disk_encryption['encryption_type']), @@ -1664,4 +1686,4 @@ class LsblkInfo(BaseModel): @classmethod def fields(cls) -> list[str]: - return [field.alias or name for name, field in cls.model_fields.items() if name != 'children'] + return [field.alias or name for name, field in cls.model_fields.items() if name != 'children'] \ No newline at end of file