From 7ee48156486101a43e90f834825dfeb0742247bd Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 00:12:03 +0100 Subject: Adding encryption helpers to the Partition() class, that sets up and utilizes luks2.encrypt() in extension. --- archinstall/lib/disk.py | 36 ++++++++++++++++++++++++++++++------ archinstall/lib/luks.py | 25 +++++++++++++++---------- examples/guided.py | 24 +++++++++++++----------- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 01a736a3..3397d7cb 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -197,6 +197,21 @@ class Partition(): return True + def encrypt(self, *args, **kwargs): + """ + A wrapper function for luks2() instances and the .encrypt() method of that instance. + """ + from .luks import luks2 + + if not self.encrypted: + raise DiskError(f"Attempting to encrypt a partition that was not marked for encryption: {self}") + + if not self.safe_to_format(): + return False + + handle = luks2(self, None, None) + return handle.encrypt(self, *args, **kwargs) + def format(self, filesystem=None, path=None, allow_formatting=None, log_formating=True): """ Format can be given an overriding path, for instance /dev/null to test @@ -204,6 +219,7 @@ class Partition(): """ if filesystem is None: filesystem = self.filesystem + if path is None: path = self.path if allow_formatting is None: @@ -349,15 +365,23 @@ class Filesystem(): """ return self.raw_parted(string).exit_code - def use_entire_disk(self, prep_mode=None): + def use_entire_disk(self, root_filesystem_type='ext4', encrypt_root_partition=True): self.add_partition('primary', start='1MiB', end='513MiB', format='vfat') self.set_name(0, 'EFI') self.set(0, 'boot on') - self.set(0, 'esp on') # TODO: Redundant, as in GPT mode it's an alias for "boot on"? https://www.gnu.org/software/parted/manual/html_node/set.html - if prep_mode == 'luks2': - self.add_partition('primary', start='513MiB', end='100%') - else: - self.add_partition('primary', start='513MiB', end='100%', format=prep_mode) + # TODO: Probably redundant because in GPT mode 'esp on' is an alias for "boot on"? + # https://www.gnu.org/software/parted/manual/html_node/set.html + self.set(0, 'esp on') + self.add_partition('primary', start='513MiB', end='100%') + + self.blockdevice.partition[0].filesystem = 'vfat' + self.blockdevice.partition[1].filesystem = root_filesystem_type + + self.blockdevice.partition[0].target_mountpoint = '/boot' + self.blockdevice.partition[1].target_mountpoint = '/' + + if encrypt_root_partition: + self.blockdevice.partition[1].encrypted = True def add_partition(self, type, start, end, format=None): log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info) diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index b98994ef..c9946239 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -16,16 +16,17 @@ class luks2(): self.filesystem = 'crypto_LUKS' def __enter__(self): - if self.partition.allow_formatting: - self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs) - else: - if not self.key_file: - self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? - - if type(self.password) != bytes: self.password = bytes(self.password, 'UTF-8') + #if self.partition.allow_formatting: + # self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs) + #else: + if not self.key_file: + self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? + + if type(self.password) != bytes: + self.password = bytes(self.password, 'UTF-8') - with open(self.key_file, 'wb') as fh: - fh.write(self.password) + with open(self.key_file, 'wb') as fh: + fh.write(self.password) return self.unlock(self.partition, self.mountpoint, self.key_file) @@ -38,6 +39,9 @@ class luks2(): def encrypt(self, partition, password=None, key_size=512, hash_type='sha512', iter_time=10000, key_file=None): # TODO: We should be able to integrate this into the main log some how. # Perhaps post-mortem? + if not self.partition.allow_formatting: + raise DiskError(f'Could not encrypt volume {self.partition} due to it having a formatting lock.') + log(f'Encrypting {partition} (This might take a while)', level=LOG_LEVELS.Info) if not key_file: @@ -49,7 +53,8 @@ class luks2(): if not password: password = self.password - if type(password) != bytes: password = bytes(password, 'UTF-8') + if type(password) != bytes: + password = bytes(password, 'UTF-8') with open(key_file, 'wb') as fh: fh.write(password) diff --git a/examples/guided.py b/examples/guided.py index 91158f9a..13bf2414 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -272,19 +272,21 @@ signal.signal(signal.SIGINT, original_sigint_handler) Once that's done, we'll hand over to perform_installation() """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: + # Wipe the entire drive if the disk flag `keep_partitions`is False. if archinstall.arguments['harddrive'].keep_partitions is False: - if archinstall.arguments.get('!encryption-password', None): - # Set a temporary partition format to indicate that the partitions is encrypted. - # Later on, we'll mount it and put an actual filesystem inside this encrypted container. - fs.use_entire_disk('luks2') - else: - fs.use_entire_disk(archinstall.arguments.get('filesystem', 'ext4')) - else: - for partition in archinstall.arguments['harddrive']: - if partition.safe_to_format(): - partition.format() + fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs'), + encrypt_root_partition=archinstall.arguments.get('!encryption-password', False)) + + # After the disk is ready, iterate the partitions and check + # which ones are safe to format, and format those. + for partition in archinstall.arguments['harddrive']: + if partition.safe_to_format(): + if partition.encrypted: + partition.encrypt(password=archinstall.arguments.get('!encryption-password', None)) else: - archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False", level=archinstall.LOG_LEVELS.Debug) + partition.format() + else: + archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=archinstall.LOG_LEVELS.Debug) if archinstall.arguments.get('!encryption-password', None): # First encrypt and unlock, then format the desired partition inside the encrypted part. -- cgit v1.2.3-70-g09d2