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它在以下脚本之前运行mdlvm这样就可以在加密卷上使用例如 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*”

Icon-warning.png
警告:切勿在您不确定其格式是“twofishSL92”还是“twofish256”的卷上运行 fsck!

用于 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”,但在较新的发行版中已更正。请始终明确指定哈希函数以避免混淆。