SDB:加密文件系统
概述
LUKS
LUKS 是一种用于加密卷的特殊磁盘格式。它将元数据放在实际加密数据的前面。元数据存储加密算法、密钥长度、块链方法等。因此,无需记住这些参数,这使得 LUKS 适用于例如 USB 存储棒。此外,LUKS 使用一个主密钥,该主密钥使用密码哈希加密。这样就可以更改密码并使用多个密码。cryptsetup 能够处理 LUKS 卷。
LUKS 是加密卷的默认和推荐格式。
“裸”磁盘格式
裸磁盘格式不存储任何关于解密卷所需参数的信息。为了访问加密数据,需要知道正确的密码和密钥派生函数(或二进制密钥本身)、加密算法以及用于计算密码块链第一个块的 IV 的方法。
大多数用户会选择 LUKS 格式,它比裸磁盘格式更方便、更不容易出错且更安全。
- 操作模式
- 磁盘上的数据以扇区存储。扇区通常由 512 字节的块组成。扇区可以随机访问。为了避免复杂的映射操作,硬盘加密也通过处理整个扇区来工作。然而,典型的块密码(如 AES 或 twofish)仅处理 16 字节的块。有各种方法可以组合块密码的多个步骤来处理更大的块(即所谓的“操作模式”)。Linux 上几乎唯一使用的方法是密码块链(CBC)。此方法需要一个所谓的初始化向量(IV)。即使明文数据相同,不同的 IV 在加密后也会产生不同的结果。因此,通过为每个扇区加密使用不同的 IV,攻击者无法判断磁盘的两个扇区是否包含相同的明文数据。扇区的 IV 通常从扇区号推导出来。计算 IV 的弱方法使卷容易受到水印攻击。
- 加密算法
- 对于硬盘加密,使用的算法是对称块算法(例如 AES 或 twofish)。这些算法将一块数据作为输入,用密钥处理它们,然后以加密形式输出相同数量的数据。加密和解密的密钥是相同的。因此,为了保持数据私密,密钥也必须保密。
- 密钥
- 密钥是特定数量的二进制数据,通常为 128、192 或 256 位(即 16、24 或 32 字节)。较长的密钥更难被攻击者猜到,但也会使加密和解密变慢。
- 哈希函数
- 加密哈希函数接受任意长度的任意数据作为输入,并输出固定数量的数据。相同的输入总是导致相同的输出。但是,给定某个输出,不可能计算出输入,即该过程只以一种方式进行。因此,哈希函数适用于从密码短语推导出加密密钥。通常用于硬盘加密的哈希函数是 SHA128、RIPEMD160 和 SHA256,产生的密钥大小分别为 128、160 和 256 位。如果哈希输出小于所需的密钥大小,通常会以某种方式多次修改并哈希密码短语。然后将哈希轮的输出连接起来。
- 密码短语
- 256 位的随机二进制数据对于人脑来说很难记住,因此通常使用密码短语作为哈希函数的输入,以生成用于加密的特定二进制密钥。密码短语越长,攻击者尝试所有可能的输入直到找到正确的加密密钥就越困难。
技术和工具
- dm-crypt
- dm-crypt 为加密实现了一个设备映射器目标。它使用内核的加密架构,因此允许使用各种加密算法。它还允许指定不同的块链和 IV 生成方法。它能够处理使用传统 cryptoloop 和 loop_fish2 创建的卷。
- cryptsetup
- cryptsetup 用于设置 dm-crypt 目标。
- loop_fish2 [已废弃]
- loop_fish2 将 twofish 算法实现为循环设备。loop_fish2 有几个缺点。它用零填充过短的密钥,并使用零作为 IV 的固定值,这从密码学的角度来看是弱点。在 openSUSE 10.3 之前,当模块加载后,就无法再使用 cryptoloop 的 twofish 实现。该模块已在 openSUSE 12.1 中移除。
- cryptoloop [已废弃]
- cryptoloop 实现了加密循环设备。它使用内核的加密架构,因此允许使用各种加密算法。它使用扇区号作为初始化向量 (IV),这容易受到水印攻击。在 openSUSE 12.2 中已移除 losetup 对 cryptoloop 的支持。
openSUSE 中的实现
从 openSUSE 10.3 开始,加密分区通过设备映射器 (dm-crypt) 而不是加密循环设备 (cryptoloop) 独占处理,原因如下:
- LUKS 已经实现在 dm-crypt 之上。
- dm-crypt 对加密分区的数量没有限制,而默认只有八个循环设备。
- 旧版 SUSE Linux 发行版使用的磁盘格式可以与新格式并行使用。
配置文件
- /etc/crypttab
- crypttab 文件包含有关加密卷的描述性信息。每个卷都在单独的行上描述;每行上的列由制表符或空格分隔。列是设备映射器目标名称、源设备、密钥文件和选项。这是指定加密卷的首选方法。为了实际挂载文件系统,还必须在/etc/fstab.
- /etc/cryptotab(已废弃)
- cryptotab 文件(注意字母“o”)也包含与 crypttab(没有“o”)类似的加密卷信息。它一直支持到 openSUSE 11.3,以兼容使用 cryptoloop/loop_fish2 的旧版 SUSE Linux 发行版。此文件中的列是循环设备、源设备、挂载点、文件系统、密码、挂载选项、信息。与 crypttab 不同,所有条目都会自动挂载,并且需要使用循环设备。在 openSUSE 11.4 中,对 cryptotab 的支持已被移除。脚本convert_cryptotab可用于手动将旧文件转换为使用 crypttab/fstab。
SysV Init 脚本(已废弃)
该/etc/init.d/boot.crypto脚本在启动期间自动设置 /etc/crypttab(以前也包括 /etc/cryptotab)中指定的所有卷。如果需要,它会提示输入密码,运行 fsck 并挂载文件系统。boot.crypto 也可以交互式地用于启动和停止单个卷。
11.1 另外引入了脚本/etc/init.d/boot.crypto-early它在以下脚本之前运行md和lvm这样就可以在加密卷上使用例如 RAID。
在 openSUSE 12.3 中,boot.crypto 脚本不再可用,因为它们已被 systemd 实现所取代。
systemd 支持
systemd 有其自己的/etc/crypttab解析器实现。它为 crypttab 中的每个条目生成服务文件。因此,例如,在/etc/crypttab中第一列名称为“cr_sda1”的条目将被命名为“systemd-cryptsetup@cr_sda1.service”。此外,所有 fstab 条目也显示为挂载单元。因此,例如,挂载 cr_sda1 的挂载点 /secret 将被称为“secret.mount”。
>=12.3
要手动挂载加密分区,包括解锁它,可以调用“systemctl start secret”。要再次禁用它,可以调用“systemctl stop secret”。可以将此类命令添加到 sudoers 文件中,以允许用户手动启动和停止加密分区。这是一个相当令人印象深刻的简化。
<=12.2
要手动挂载加密分区,包括解锁它,可以调用“systemctl start secret.mount”。要再次禁用它,可以调用“systemctl stop systemd-cryptsetup@cr_sda1.service”。可以将此类命令添加到 sudoers 文件中,以允许用户手动启动和停止加密分区。
initrd 支持
mkinitrd 的钩子脚本允许在 initrd 中解锁 LUKS 卷。加密的根文件系统会自动检测,其他卷需要在/etc/crypttab.
中具有“initrd”选项。
cryptsetup 命令可用于将分区准备为 LUKS 卷。以下命令(以 root 身份)将准备/dev/sda3进行加密。该命令还将提示输入用于加密主密钥的密码
cryptsetup luksFormat /dev/sda3
要访问内容,设备需要打开
cryptsetup luksOpen /dev/sda3 my_secure_partion
该设备现在显示为/dev/mapper/my_secure_partion。为了有用,需要在其上创建文件系统
mkfs.ext4 /dev/mapper/my_secure_partion
现在可以挂载分区并填充文件
mount /dev/mapper/my_secure_partion /secret
完成后,分区需要卸载并关闭,以便未经提供密码就无法访问
umount /secret cryptsetup luksClose /dev/mapper/my_secure_partion
要使分区在启动时解密并挂载,需要/etc/crypttab和/etc/fstab中的条目
/etc/crypttab:
my_secure_partion <device> none luks
地点device将替换为/dev/sda3或替换为UUID=<luksUUID>一样,luksUUID通过以下方式获取
cryptsetup luksUUID /dev/sda3
/etc/fstab:
/dev/mapper/my_secure_partion /secret ext4 nofail 0 2
最后,init 脚本需要激活
chkconfig boot.crypto on chkconfig boot.crypto-early on
将 cryptoloop 卷迁移到 dm-crypt
从 openSUSE 12.2 开始,不再支持 cryptoloop。不过,旧卷仍然可以通过 dm-crypt 访问。脚本 convert_cryptotab 有助于转换旧的 /etc/cryptotab 条目。
以下部分提供了一些手动转换条目的示例。
/etc/fstab 中列出的加密文件
由于 losetup 和 mount 共享相同的源,因此可以通过 fstab 让 mount 设置 cryptoloop 设备。这对于 dm-crypt 不再可能。
twofish256 cryptoloop 镜像
以下示例显示了 YaST 通常创建的 cryptoloop 镜像。
旧etc/fstab用于 twofish256 cryptoloop 镜像
/secret.img /secret ext2 noauto,acl,user_xattr,loop=/dev/loop1,encryption=twofish256,phash=sha512,itercountk=100 0 0
要使用 dm-crypt 访问相同的卷,需要将与加密相关的参数放入/etc/crypttab,而挂载选项需要保留在fstab:
新/etc/crypttab用于 twofish256 cryptoloop 镜像
secret /secret.img none cipher=twofish-cbc-plain,size=256,hash=sha512,itercountk=100
/etc/fstab以实际挂载卷
/dev/mapper/secret /secret ext2 nofail,acl,user_xattr 0 2
手动挂载文件的命令
旧
losetup -e twofish256 /dev/loop0 /secret.img mount /dev/loop0 /secret
新
losetup /dev/loop0 /secret.img cryptsetup --hash sha512 --cipher twofish-cbc-plain --key-size 256 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
aes cryptoloop 镜像
此示例显示了一个使用 aes 算法手动创建的 cryptoloop 镜像
旧/etc/fstab用于 aes cryptoloop 镜像
/secret.img /secret ext2 nofail,user,loop,encryption=aes 0 2
请注意,上面的 fstab 既没有指定密钥长度,也没有指定哈希算法。隐式默认值为 128 位密钥长度和 sha256 哈希算法。
新/etc/crypttab用于 aes cryptoloop 镜像
secret /secret.img none cipher=aes-cbc-plain,size=128,hash=sha256
/etc/fstab以实际挂载卷
/dev/mapper/secret /secret ext2 nofail,user 0 2
手动挂载文件的命令
旧
losetup -e aes /dev/loop0 /secret.img mount /dev/loop0 /secret
新
losetup /dev/loop0 /secret.img cryptsetup --hash sha256 --cipher aes-cbc-plain --key-size 128 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
新:cryptsetup >= 1.6.4 (leap 42.1)
losetup /dev/loop0 /secret.img echo "<password>" | cryptsetup loopaesOpen --key-file=- /dev/loop0 secret_img mount /dev/mapper/secret_img /secret
非常旧的 twofish 卷
使用旧发行版(如 SuSE Linux 8.1)上的 loop_fish2 模块创建的卷在 cryptotab 中被列为“twofish”。
用于 twofish 分区的旧 /etc/cryptotab
/dev/loop4 /secret.img /secret ext2 twofish acl,user_xattr
用于 twofish 分区的新 /etc/crypttab
secret /secret.img none cipher=twofish-cbc-null,hash=ripemd160:20,size=192
手动挂载文件的命令
旧
losetup -e twofish /dev/loop0 /secret.img mount /dev/loop0 /secret
新
losetup /dev/loop0 /secret.img cryptsetup --hash ripemd160:20 --cipher twofish-cbc-null --key-size 192 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
twofishSL92 卷
在 SUSE Linux 9.2 上,YaST 不再使用 192 位密钥长度,而是使用 256 位。不幸的是,twofish 加密与该密钥长度可以由 loop_fish2 和 cryptoloop 提供。这两个模块之间的区别是 IV 生成方法,这导致磁盘格式的细微变化。loop_fish2 使用的格式后来被命名为“twofishSL92”,以便能够将其与 cryptoloop 的“twofish256”区分开来。必须特别注意不要使用错误的格式。使用错误的格式可能导致文件系统完全损坏!twofishSL92 格式的 dm-crypt 表示法是“twofish-cbc-*null*”,而 twofish256 的表示法是“twofish-cbc-*plain*”
用于 twofishSL92 分区的旧 /etc/cryptotab
/dev/loop0 /secret.img /secret ext2 twofishSL92 acl,user_xattr
用于 twofishSL92 分区的新 /etc/crypttab
secret /secret.img none cipher=twofish-cbc-null,hash=sha512,size=256
手动挂载文件的命令
旧
losetup -e twofishSL92 /dev/loop0 /secret.img mount /dev/loop0 /secret
新
losetup /dev/loop0 /secret.img cryptsetup --hash sha512 --cipher twofish-cbc-null --key-size 256 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
修复损坏的 Initrd
有时创建 initrd 会出错,需要从救援系统内部重新创建。对于 LUKS 内的 LVM,这需要一些此处概述的手动步骤。
以下步骤假设您的设备是 /dev/sda2,并且卷组名为“system”。请根据需要调整。
将 LUKS 容器解锁为 /dev/mapper/XXX。如果您已经知道目标名称,可以立即输入(对于 /dev/sda2 应该是 cr_sda2)
# cryptsetup luksOpen /dev/sda2 XXX
启用 LVM 卷组并挂载根设备
# vgchange -a y # mount /dev/system/root /mnt
将 XXX 重命名为设备映射器目标的预期名称。它是 /etc/crypttab 的第一列。在运行 mkinitrd 之前使用正确的名称很重要。否则,系统将尝试解锁卷两次!
# cat /mnt/etc/crypttab cr_sda2 /dev/sda2 none none # dmsetup rename XXX cr_sda2
chroot 进入系统以修复所需的一切
# for i in sys dev proc; do mount --bind /$i /mnt/$i; done # chroot /mnt su - # mount -a # mkinitrd # umount /boot # exit
卸载并清理
# for i in sys dev proc; do umount /mnt/$i; done # umount /mnt # vgchange -a n # dmsetup remove cr_sda2
已知错误和陷阱
“noauto” fstab 选项
过去,yast 为加密卷创建带有“noauto”选项的 fstab 条目。这是必要的,因为 boot.crypto 在 boot.localfs 之后运行并自行挂载卷。现在,存在 fstab 选项“nofail”,它允许启动脚本在可能的情况下挂载卷,但如果卷失败则继续启动。由于 sysv 脚本不再与 systemd 一起使用,并且 systemd 严格遵守“noauto”选项,因此旧的 fstab 条目必须转换为使用“nofail”。
还建议将 fstab 中的 fs_passno 列(第六个字段)设置为“2”以启用文件系统检查。
国际键盘布局
在使用非美式键盘布局更改密码时,请确保不要输入只能通过特殊 X 输入法获得的字符。boot.crypto 脚本只遵守 /etc/sysconfig/keyboard 中的设置,这可能与 X 键盘布局不同。当使用加密根分区时,根本不支持非美式布局,因为 initrd 目前不支持包含键盘映射。
启动时两次请求密码
要解决此问题,请参阅避免两次输入密码。
openSUSE 10.3
- 最初,“mount”和“losetup”无法设置使用旧版“loop_fish2”内核模块(“twofish”、“twofishSL92”)而不是“cryptoloop”的镜像。一次在线更新重新引入了该功能。与以前的发行版相比,“loop_fish2”模块的存在不再改变“twofish256”的含义(另请参阅#twofishSL92_volume)。
- 以前,对于 128 位密钥长度的算法(例如“aes128”),隐式默认哈希函数是“sha256”。在 10.3 中,它意外地是“sha512”,但在较新的发行版中已更正。请始终明确指定哈希函数以避免混淆。

