new ciphers
This commit is contained in:
parent
f8a202d843
commit
ed7ba45ae3
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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']
|
||||
Loading…
Reference in New Issue