fix the problems for filesystems

This commit is contained in:
Alperen42v 2026-07-02 13:23:54 +03:00
parent 8eec5a731a
commit 228a86c474
4 changed files with 21 additions and 82 deletions

View File

@ -282,7 +282,6 @@ class DeviceHandler:
lock_after_create: bool = True, lock_after_create: bool = True,
iter_time: int = DEFAULT_ITER_TIME, iter_time: int = DEFAULT_ITER_TIME,
cipher: str = DEFAULT_CIPHER, cipher: str = DEFAULT_CIPHER,
integrity: str | None = None,
) -> Luks2: ) -> Luks2:
luks_handler = Luks2( luks_handler = Luks2(
dev_path, dev_path,
@ -290,7 +289,7 @@ class DeviceHandler:
password=enc_password, password=enc_password,
) )
key_file = luks_handler.encrypt(iter_time=iter_time, cipher=cipher, integrity=integrity) key_file = luks_handler.encrypt(iter_time=iter_time, cipher=cipher)
udev_sync() udev_sync()
@ -321,7 +320,7 @@ class DeviceHandler:
password=enc_conf.encryption_password, password=enc_conf.encryption_password,
) )
key_file = luks_handler.encrypt(iter_time=enc_conf.iter_time, cipher=enc_conf.cipher, integrity=enc_conf.integrity) key_file = luks_handler.encrypt(iter_time=enc_conf.iter_time, cipher=enc_conf.cipher)
udev_sync() udev_sync()

View File

@ -7,7 +7,6 @@ from archinstall.lib.menu.helpers import Input, Selection, Table
from archinstall.lib.menu.menu_helper import MenuHelper from archinstall.lib.menu.menu_helper import MenuHelper
from archinstall.lib.menu.util import get_password from archinstall.lib.menu.util import get_password
from archinstall.lib.models.device import ( from archinstall.lib.models.device import (
AEAD_CIPHERS,
DEFAULT_CIPHER, DEFAULT_CIPHER,
DEFAULT_ITER_TIME, DEFAULT_ITER_TIME,
DeviceModification, DeviceModification,
@ -114,17 +113,7 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]):
return [] return []
async def _select_cipher(self, preset: str | None) -> str | None: async def _select_cipher(self, preset: str | None) -> str | None:
cipher = await select_encryption_cipher(preset) return await select_encryption_cipher(preset)
# AEAD ciphers (e.g. chacha20-random) require LUKS2 + --integrity;
# keep the underlying DiskEncryption.integrity in sync automatically
# so the user never has to set it manually or risk an invalid combo.
if cipher in AEAD_CIPHERS:
self._enc_config.integrity = AEAD_CIPHERS[cipher]
else:
self._enc_config.integrity = None
return cipher
def _check_dep_enc_type(self) -> bool: def _check_dep_enc_type(self) -> bool:
enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value
@ -168,9 +157,6 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]):
enc_partitions = [] enc_partitions = []
if enc_type != EncryptionType.NO_ENCRYPTION and enc_password and (enc_partitions or enc_lvm_vols): if enc_type != EncryptionType.NO_ENCRYPTION and enc_password and (enc_partitions or enc_lvm_vols):
cipher = cipher or DEFAULT_CIPHER
integrity = AEAD_CIPHERS.get(cipher)
return DiskEncryption( return DiskEncryption(
encryption_password=enc_password, encryption_password=enc_password,
encryption_type=enc_type, encryption_type=enc_type,
@ -178,8 +164,7 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]):
lvm_volumes=enc_lvm_vols, lvm_volumes=enc_lvm_vols,
hsm_device=enc_config.hsm_device, hsm_device=enc_config.hsm_device,
iter_time=iter_time or DEFAULT_ITER_TIME, iter_time=iter_time or DEFAULT_ITER_TIME,
cipher=cipher, cipher=cipher or DEFAULT_CIPHER,
integrity=integrity,
) )
return None return None
@ -231,13 +216,7 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]):
def _prev_cipher(self, item: MenuItem) -> str | None: def _prev_cipher(self, item: MenuItem) -> str | None:
cipher = self._item_group.find_by_key('cipher').value cipher = self._item_group.find_by_key('cipher').value
if cipher: if cipher:
output = f'{tr("Encryption cipher")}: {cipher}' return f'{tr("Encryption cipher")}: {cipher}'
if cipher in AEAD_CIPHERS:
integrity = AEAD_CIPHERS[cipher]
output += f'\n{tr("Integrity")}: {integrity} ({tr("requires LUKS2")})'
return output
return None return None
def _prev_partitions(self, item: MenuItem) -> str | None: def _prev_partitions(self, item: MenuItem) -> str | None:
@ -452,9 +431,6 @@ async def select_iteration_time(preset: int | None = None) -> int | None:
async def select_encryption_cipher(preset: str | None = None) -> str | None: async def select_encryption_cipher(preset: str | None = None) -> str | None:
# Regular block-cipher modes: accepted directly by `cryptsetup --cipher`. # Regular block-cipher modes: accepted directly by `cryptsetup --cipher`.
# AEAD modes (see AEAD_CIPHERS in models/device.py) need LUKS2 and a
# separate --integrity value, which DiskEncryption.__post_init__ and
# DiskEncryptionMenu._select_cipher fill in automatically.
options = [ options = [
'aes-xts-plain64', 'aes-xts-plain64',
'aes-cbc-essiv:sha256', 'aes-cbc-essiv:sha256',

View File

@ -3,13 +3,12 @@ from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from subprocess import CalledProcessError from subprocess import CalledProcessError
from types import TracebackType from types import TracebackType
from typing import cast
from archinstall.lib.command import SysCommand, SysCommandWorker, run from archinstall.lib.command import SysCommand, SysCommandWorker, run
from archinstall.lib.disk.utils import get_lsblk_info, umount from archinstall.lib.disk.utils import get_lsblk_info, umount
from archinstall.lib.exceptions import DiskError, SysCallError from archinstall.lib.exceptions import DiskError, SysCallError
from archinstall.lib.log import debug, info from archinstall.lib.log import debug, info
from archinstall.lib.models.device import AEAD_CIPHERS, DEFAULT_CIPHER, DEFAULT_ITER_TIME from archinstall.lib.models.device import CIPHER_KEY_SIZES, DEFAULT_CIPHER, DEFAULT_ITER_TIME
from archinstall.lib.models.users import Password from archinstall.lib.models.users import Password
from archinstall.lib.utils.util import generate_password from archinstall.lib.utils.util import generate_password
@ -75,19 +74,15 @@ class Luks2:
iter_time: int = DEFAULT_ITER_TIME, iter_time: int = DEFAULT_ITER_TIME,
key_file: Path | None = None, key_file: Path | None = None,
cipher: str = DEFAULT_CIPHER, cipher: str = DEFAULT_CIPHER,
integrity: str | None = None,
) -> Path | None: ) -> Path | None:
debug(f'Luks2 encrypting: {self.luks_dev_path}') debug(f'Luks2 encrypting: {self.luks_dev_path}')
key_file_arg, passphrase = self._get_passphrase_args(key_file) key_file_arg, passphrase = self._get_passphrase_args(key_file)
is_aead = cipher in AEAD_CIPHERS # Resolve the correct key size for this cipher.
# XTS mode uses two keys (e.g. 256+256 = 512 bits for aes-xts-plain64),
if is_aead and not integrity: # CBC mode uses a single key (max 256 bits for aes-cbc-essiv:sha256).
integrity = AEAD_CIPHERS[cipher] resolved_key_size = CIPHER_KEY_SIZES.get(cipher, key_size)
if integrity and not is_aead:
raise DiskError(f'Integrity option "{integrity}" is only valid for AEAD ciphers, not "{cipher}"')
cmd = [ cmd = [
'cryptsetup', 'cryptsetup',
@ -99,22 +94,12 @@ class Luks2:
'argon2id', 'argon2id',
'--cipher', '--cipher',
cipher, cipher,
'--hash',
hash_type,
'--key-size',
str(resolved_key_size),
] ]
if is_aead:
# AEAD ciphers (e.g. chacha20-random) authenticate each sector via
# --integrity and do not take --hash or a fixed --key-size the same
# way length-preserving modes (aes-xts-plain64 etc.) do; key size is
# derived from the cipher/integrity combination by cryptsetup itself.
cmd += ['--integrity', cast(str, integrity)]
else:
cmd += [
'--hash',
hash_type,
'--key-size',
str(key_size),
]
cmd += [ cmd += [
'--iter-time', '--iter-time',
str(iter_time), str(iter_time),

View File

@ -1464,15 +1464,15 @@ class EncryptionType(StrEnum):
DEFAULT_CIPHER = 'aes-xts-plain64' DEFAULT_CIPHER = 'aes-xts-plain64'
# AEAD (Authenticated Encryption with Associated Data) ciphers require LUKS2 # XTS mode splits the key in two halves so needs double the bits.
# and a separate --integrity parameter; they cannot be used like normal # CBC/ECB use the key directly — max 256 bit.
# block-cipher + chainmode + ivmode strings (e.g. aes-xts-plain64). CIPHER_KEY_SIZES: dict[str, int] = {
# Mapping: cipher value used in --cipher -> required --integrity value 'aes-xts-plain64': 512, # XTS: 256+256
AEAD_CIPHERS: dict[str, str] = { 'aes-cbc-essiv:sha256': 256, # CBC: single 256-bit key
'aes-gcm-random': 'aead', 'serpent-xts-plain64': 512, # XTS: 256+256
'twofish-xts-plain64': 512, # XTS: 256+256
} }
class _DiskEncryptionSerialization(TypedDict): class _DiskEncryptionSerialization(TypedDict):
encryption_type: str encryption_type: str
partitions: list[str] partitions: list[str]
@ -1480,7 +1480,6 @@ class _DiskEncryptionSerialization(TypedDict):
hsm_device: NotRequired[_Fido2DeviceSerialization] hsm_device: NotRequired[_Fido2DeviceSerialization]
iter_time: NotRequired[int] iter_time: NotRequired[int]
cipher: NotRequired[str] cipher: NotRequired[str]
integrity: NotRequired[str]
@dataclass @dataclass
@ -1492,7 +1491,6 @@ class DiskEncryption:
hsm_device: Fido2Device | None = None hsm_device: Fido2Device | None = None
iter_time: int = DEFAULT_ITER_TIME iter_time: int = DEFAULT_ITER_TIME
cipher: str = DEFAULT_CIPHER cipher: str = DEFAULT_CIPHER
integrity: str | None = None
def __post_init__(self) -> None: def __post_init__(self) -> None:
if self.encryption_type in [EncryptionType.LUKS, EncryptionType.LVM_ON_LUKS] and not self.partitions: if self.encryption_type in [EncryptionType.LUKS, EncryptionType.LVM_ON_LUKS] and not self.partitions:
@ -1501,20 +1499,6 @@ class DiskEncryption:
if self.encryption_type == EncryptionType.LUKS_ON_LVM and not self.lvm_volumes: if self.encryption_type == EncryptionType.LUKS_ON_LVM and not self.lvm_volumes:
raise ValueError('LuksOnLvm encryption require LMV volumes to be defined') raise ValueError('LuksOnLvm encryption require LMV volumes to be defined')
# AEAD ciphers (chacha20-random, aes-gcm-random) are only valid on LUKS2
# and require --integrity to be set; auto-fill it if missing so the
# cryptsetup call downstream doesn't end up with an invalid combination.
if self.cipher in AEAD_CIPHERS:
required_integrity = AEAD_CIPHERS[self.cipher]
if not self.integrity:
self.integrity = required_integrity
elif self.integrity != required_integrity:
raise ValueError(
f'Cipher {self.cipher!r} requires integrity {required_integrity!r}, got {self.integrity!r}'
)
elif self.integrity:
raise ValueError(f'Integrity option is only valid for AEAD ciphers, not {self.cipher!r}')
def should_generate_encryption_file(self, dev: PartitionModification | LvmVolume) -> bool: def should_generate_encryption_file(self, dev: PartitionModification | LvmVolume) -> bool:
if isinstance(dev, PartitionModification): if isinstance(dev, PartitionModification):
return dev in self.partitions and dev.mountpoint != Path('/') return dev in self.partitions and dev.mountpoint != Path('/')
@ -1537,9 +1521,6 @@ class DiskEncryption:
if self.cipher != DEFAULT_CIPHER: # Only include if not default if self.cipher != DEFAULT_CIPHER: # Only include if not default
obj['cipher'] = self.cipher obj['cipher'] = self.cipher
if self.integrity:
obj['integrity'] = self.integrity
return obj return obj
@staticmethod @staticmethod
@ -1585,7 +1566,6 @@ class DiskEncryption:
volumes.append(vol) volumes.append(vol)
cipher = disk_encryption.get('cipher', None) or DEFAULT_CIPHER cipher = disk_encryption.get('cipher', None) or DEFAULT_CIPHER
integrity = disk_encryption.get('integrity', None)
enc = cls( enc = cls(
EncryptionType(disk_encryption['encryption_type']), EncryptionType(disk_encryption['encryption_type']),
@ -1593,7 +1573,6 @@ class DiskEncryption:
enc_partitions, enc_partitions,
volumes, volumes,
cipher=cipher, cipher=cipher,
integrity=integrity,
) )
if hsm := disk_encryption.get('hsm_device', None): if hsm := disk_encryption.get('hsm_device', None):