我有一个卢克斯(Linux 统一密钥设置)包含 rootfs 的分区。我希望将其替换为包含相同 rootfs 的未加密 ext4 分区。经过广泛搜索后,我没有看到任何工具可以帮助完成此过程。我错过了什么?
如果没有解决办法是什么?使用parted
删除LUKS分区,创建ext4分区并将rootfs复制到其中?
答案1
这是一个高度危险操作,应非常小心地执行。
在最简单的层面上,有一个实用程序称为cryptsetup-重新加密允许进行此操作。它在其手册页中明确指出:
WARNING: The cryptsetup-reencrypt program is not resistant to
hardware or kernel failures during reencryption (you can lose your
data in this case).
ALWAYS BE SURE YOU HAVE RELIABLE BACKUP BEFORE USING THIS TOOL.
The reencryption can be temporarily suspended (by TERM signal or by
using ctrl+c) but you need to retain temporary files named
LUKS-<uuid>.[log|org|new]. LUKS device is unavailable until
reencryption is finished though.
根据手册页的“示例”部分:
Remove LUKS encryption completely
cryptsetup-reencrypt /dev/sdb1 --decrypt
这可能需要在“实时”环境中完成(意味着完全运行的临时 Linux 环境,如由费多拉现场或者乌班图直播。
作为此工作流程的替代方案,您还可以采取更明确的方式备份数据、删除分区并重新创建分区。 Arch Linux 提供了关于此工作流程的优秀文档以及其他故障排除步骤:
https://wiki.archlinux.org/index.php/Removing_System_Encryption
再次强调,这不是一个简单的操作,在发生灾难性故障时,所有数据的备份至关重要。
答案2
正如 @BrianRedbeard 所说,有一个工具可以实现此目的 ( cryptsetup-reencrypt
)。仔细阅读相关文档。这是一项危险的操作。 (就地数据转换总是如此。一步错误,一切都会化为乌有。)
只是为了好玩,手动过程:
实际上这很简单(并且这样行不通在另一个方向!)。实际上你可以像这样复制它:
pv < /dev/mapper/cryptsdx1 > /dev/sdx1
但由于我们正在读取和写入同一物理设备,因此使用dd
大块大小可能会更快(前提是您有足够的 RAM)。在 HDD 上,这可能会更快,因为它执行的查找次数较少,并且查找速度很慢。
dd status=progress bs=1G iflag=fullblock if=/dev/mapper/cryptsdx1 of=/dev/sdx1
但首先,您应该备份您的 LUKS 标头,因为 LUKS 标头是您在此过程中将覆盖的第一个内容,即使您想恢复也无法恢复。
cryptsetup luksHeaderBackup /dev/sdx1 --header-backup-file myluksheader.backup
并确保备份安全,而不仅仅是保存在 LiveCD 环境的 RAM 中。
LUKS设备基本上是这样的:
| LUKS HEADER | ENCRYPTED DATA |
在 pv / dd 之后,它应该如下所示:
| DECRYPTED DATA | FREE SPACE |
因此 LUKS 标头位于设备的开头,大小约为 2MiB(以前是 1MiB 加上几个扇区)。由于我们正在摆脱它,设备末端将有可用空间,您可以将文件系统增加 2MiB。哎哟!
因此,数据本身可以在偏移量处找到(通常为 2MiB,请使用 进行检查cryptsetup luksDump
)。这个偏移量在这里很重要 - 这意味着数据不仅需要解密,而且还需要移动 - 解密的开始将出现在最初存储 LUKS 标头的位置。
这也意味着在整个过程中,将存在以解密和加密形式存在的重叠区域。如果机器崩溃并且您必须找到恢复点,这非常有用。
那么,万一发生车祸该怎么办呢?
首先,您必须使用备份重新创建加密设备:
cryptsetup --header myluksheader.backup luksOpen /dev/sdx1 cryptsdx1
然后找到重叠点:
skip=0 # or skip=X if you're sure at least X bytes were copied
step=$((1024*1024)) # 1MiB, use 512KiB for old 1MiB headers (offset / 2)
while ! cmp --bytes=$step /dev/sdx1 /dev/mapper/cryptsdx1 $skip $skip
do
skip=$(($skip+$step))
done
cmp --bytes=$step /dev/sdx1 /dev/mapper/cryptsdx1 $skip $skip && echo $skip || echo fail
最后继续:
dd status=progress bs=1G iflag=fullblock,skip_bytes oflag=seek_bytes \
skip=$skip seek=$skip if=/dev/mapper/cryptsdx1 of=/dev/sdx1
在实际文件系统上使用任一方法之前,值得在不相关的分区(甚至只是循环设备)上进行练习运行,以确保它仍然有效。
例如,我在这里没有考虑新的 LUKS2 格式,其基本形式的工作方式相同(4MiB 标头),但它支持奇怪的东西,例如多个数据段等。因此,如果您正在使用此类功能,那就有点复杂了(而且我认为cryptsetup-reencrypt
还没有涵盖这一点)。