加密根文件系统 HOWTO

Christophe Devine

修订历史
版本 v1.32005-03-13修订者:cd
更新了软件包版本。
版本 v1.22004-10-20修订者:cd
更新了软件包版本。
版本 v1.12003-12-01修订者:cd
增加了对 GRUB 的支持。
版本 v1.02003-09-24修订者:cd
初始版本,由 LDP 审核。
版本 v0.92003-09-11修订者:cd
更新并转换为 DocBook XML。

本文档解释了如何使用强加密技术加密您的 Linux 根文件系统,从而保护您的个人数据安全。

本 HOWTO 根据 GNU 自由文档许可证 1.2 版发布。


目录
1. 准备系统
1.1. 设置分区布局
1.2. 必需的软件包
1.3. 安装 Linux-2.4.29
1.4. 安装 Linux-2.6.10
1.5. 安装 util-linux-2.12p
2. 创建加密根文件系统
3. 设置启动设备
3.1. 创建 ramdisk
3.2. 从 CD-ROM 启动
3.3. 从硬盘分区启动
4. 最后步骤
5. 关于本 HOWTO

1. 准备系统

1.1. 设置分区布局

您的硬盘 (hda) 应该至少包含三个分区

  • hda1:这个小的未加密分区将要求输入密码,以便挂载加密的根文件系统。

  • hda2:这个分区将包含您的加密根文件系统;请确保它足够大。

  • hda3:这个分区保存当前的 GNU/Linux 系统。

此时,hda1 和 hda2 都是未使用的。hda3 是您当前安装 Linux 发行版的位置;/usr 和 /boot 不能 与此分区分离。

以下是您的分区布局可能的外观示例

# fdisk -l /dev/hda

Disk /dev/hda: 255 heads, 63 sectors, 2432 cylinders
Units = cylinders of 16065 * 512 bytes

   Device Boot    Start       End    Blocks   Id  System
/dev/hda1             1         1      8001   83  Linux
/dev/hda2             2       263   2104515   83  Linux
/dev/hda3           264       525   2104515   83  Linux
/dev/hda4           526      2047  12225465   83  Linux


1.2. 必需的软件包

如果您使用 Debian,则以下软件包是必需的

apt-get install gcc make libncurses5-dev patch bzip2 wget

为了方便复制和粘贴,您还应该安装

apt-get install lynx gpm


1.3. 安装 Linux-2.4.29

有两个主要的项目在内核中添加了环回加密支持:cryptoloop 和 loop-AES。本 HOWTO 基于 loop-AES,因为它具有极其快速且高度优化的 Rijndael 汇编语言实现,因此如果您有 IA-32 (x86) CPU,则可以提供最佳性能。此外,关于 cryptoloop 存在一些 安全问题

首先,下载并解压 loop-AES 软件包

cd /usr/src
wget http://loop-aes.sourceforge.net/loop-AES/loop-AES-v3.0b.tar.bz2
tar -xvjf loop-AES-v3.0b.tar.bz2

然后您必须下载并修补内核源代码

wget http://ftp.kernel.org/pub/linux/kernel/v2.4/linux-2.4.29.tar.bz2
tar -xvjf linux-2.4.29.tar.bz2
cd linux-2.4.29
rm include/linux/loop.h drivers/block/loop.c
patch -Np1 -i ../loop-AES-v3.0b/kernel-2.4.28.diff

设置键盘映射

dumpkeys | loadkeys -m - > drivers/char/defkeymap.c

接下来,配置您的内核;确保设置了以下选项

make menuconfig

    Block devices  --->

        <*> Loopback device support
        [*]   AES encrypted loop device support (NEW)

        <*> RAM disk support
        (4096)   Default RAM disk size (NEW)
        [*]   Initial RAM disk (initrd) support

    File systems  --->

        <*> Ext3 journalling file system support
        <*> Second extended fs support

(important note: do not enable /dev file system support)

编译内核并安装它

make dep bzImage
make modules modules_install
cp arch/i386/boot/bzImage /boot/vmlinuz

如果 grub 是您的引导加载程序,请更新 /boot/grub/menu.lst 或 /boot/grub/grub.conf

cat > /boot/grub/menu.lst << EOF
default 0
timeout 10
color green/black light-green/black
title Linux
    root (hd0,2)
    kernel /boot/vmlinuz ro root=/dev/hda3
EOF

否则,更新 /etc/lilo.conf 并运行 lilo

cat > /etc/lilo.conf << EOF
lba32
boot=/dev/hda
prompt
timeout=60
image=/boot/vmlinuz
    label=Linux
    read-only
    root=/dev/hda3
EOF
lilo

您现在可以重启系统。


1.4. 安装 Linux-2.6.10

按照上一节中的描述进行操作,使用 loop-aes 的 kernel-2.6.10.diff 补丁代替,并确保 激活 cryptoloop 支持。请注意,模块支持要求您安装了 module-init-tools 软件包。


1.5. 安装 util-linux-2.12p

losetup 程序是 util-linux 软件包的一部分,必须对其进行修补和重新编译,以添加强加密支持。下载、解压并修补 util-linux

cd /usr/src
wget http://ftp.kernel.org/pub/linux/utils/util-linux/util-linux-2.12p.tar.bz2
tar -xvjf util-linux-2.12p.tar.bz2
cd util-linux-2.12p
patch -Np1 -i ../loop-AES-v3.0b/util-linux-2.12p.diff

要使用少于 20 个字符的密码,请输入

CFLAGS="-O2 -DLOOP_PASSWORD_MIN_LENGTH=8"; export CFLAGS

安全当然是您主要关心的问题。因此,请不要启用少于 20 个字符的密码。数据隐私不是免费的,必须以长密码的形式“支付”。

编译 losetup 并以 root 身份安装它

./configure && make lib mount
mv -f /sbin/losetup /sbin/losetup~
rm -f /usr/share/man/man8/losetup.8*
cd mount
gzip losetup.8
cp losetup /sbin
cp losetup.8.gz /usr/share/man/man8/
chattr +i /sbin/losetup


2. 创建加密根文件系统

用随机数据填充目标分区

shred -n 1 -v /dev/hda2

设置加密环回设备

losetup -e aes256 -S xxxxxx /dev/loop0 /dev/hda2

为了防止优化的字典攻击,建议添加 -S xxxxxx 选项,其中 “xxxxxx” 是您随机选择的种子(例如,您可以选择 “gPk4lA”)。将您的种子写在一张纸上,以免之后丢失。此外,为了避免启动时键盘映射出现问题,请不要在密码中使用非 ASCII 字符(重音符号等)。Diceware 站点提供了一种简单的方法来创建强大但易于记忆的密码短语。

现在创建 ext3 文件系统

mke2fs -j /dev/loop0

检查您输入的密码是否正确

losetup -d /dev/loop0
losetup -e aes256 -S xxxxxx /dev/loop0 /dev/hda2

mkdir /mnt/efs
mount /dev/loop0 /mnt/efs

您可以比较加密和未加密的数据

xxd /dev/hda2  | less
xxd /dev/loop0 | less

现在是安装加密 Linux 系统的时候了。如果您使用 GNU/Linux 发行版(例如 Debian、Slackware、Gentoo、Mandrake、RedHat/Fedora、SuSE 等),请运行以下命令

cp -avx / /mnt/efs

如果您使用 Linux From Scratch 书籍,请按照手册中的描述进行操作,并进行以下修改


3. 设置启动设备

3.1. 创建 ramdisk

首先,chroot 进入加密分区并创建启动设备挂载点

chroot /mnt/efs
mkdir /loader

然后,创建初始 ramdisk (initrd),稍后将需要它

cd
dd if=/dev/zero of=initrd bs=1k count=4096
mke2fs -F initrd
mkdir ramdisk
mount -o loop initrd ramdisk

如果您使用 grsecurity,您可能会收到 “Permission denied” 错误消息;在这种情况下,您必须在 chroot 之外运行 mount 命令。

创建文件系统层次结构并将所需文件复制到其中

mkdir ramdisk/{bin,dev,lib,mnt,sbin}
cp /bin/{bash,mount} ramdisk/bin/
ln -s bash ramdisk/bin/sh
mknod -m 600 ramdisk/dev/console c 5 1
mknod -m 600 ramdisk/dev/hda2    b 3 2
mknod -m 600 ramdisk/dev/loop0   b 7 0
cp /lib/{ld-linux.so.2,libc.so.6,libdl.so.2} ramdisk/lib/
cp /lib/{libncurses.so.5,libtermcap.so.2}    ramdisk/lib/
cp /sbin/{losetup,pivot_root} ramdisk/sbin/

如果您看到类似 “/lib/libncurses.so.5: No such file or directory” 或 “/lib/libtermcap.so.2: No such file or directory” 的消息,这是正常的;bash 只需要这两个库中的一个。您可以使用以下命令检查实际需要哪个库

ldd /bin/bash

编译 sleep 程序,这将防止密码提示被内核消息(例如正在注册的 usb 设备)淹没。

cat > sleep.c << "EOF"
#include <unistd.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
    if( argc == 2 )
        sleep( atoi( argv[1] ) );

    return( 0 );
}
EOF

gcc -s sleep.c -o ramdisk/bin/sleep
rm sleep.c

创建 init 脚本

cat > ramdisk/sbin/init << "EOF"
#!/bin/sh

/bin/sleep 3

echo -n "Enter seed value: "
read SEED

/sbin/losetup -e aes256 -S $SEED /dev/loop0 /dev/hda2
/bin/mount -r -n -t ext3 /dev/loop0 /mnt

while [ $? -ne 0 ]
do
    /sbin/losetup -d /dev/loop0
    /sbin/losetup -e aes256 -S $SEED /dev/loop0 /dev/hda2
    /bin/mount -r -n -t ext3 /dev/loop0 /mnt
done

cd /mnt
/sbin/pivot_root . loader
exec /usr/sbin/chroot . /sbin/init
EOF

chmod 755 ramdisk/sbin/init

卸载环回设备并压缩 initrd

umount -d ramdisk
rmdir ramdisk
gzip initrd
mv initrd.gz /boot/


3.2. 从 CD-ROM 启动

我强烈建议您使用只读介质(例如可引导 CD-ROM)启动系统。

下载并解压 syslinux

wget http://ftp.kernel.org/pub/linux/utils/boot/syslinux/syslinux-3.07.tar.bz2
tar -xvjf syslinux-3.07.tar.bz2

配置 isolinux

mkdir bootcd
cp /boot/{vmlinuz,initrd.gz} syslinux-3.07/isolinux.bin bootcd
echo "DEFAULT /vmlinuz initrd=initrd.gz ro root=/dev/ram0" \
    > bootcd/isolinux.cfg

创建并刻录可引导 cd-rom iso 镜像

mkisofs -o bootcd.iso -b isolinux.bin -c boot.cat \
        -no-emul-boot -boot-load-size 4 -boot-info-table \
        -J -hide-rr-moved -R bootcd/

cdrecord -dev 0,0,0 -speed 4 -v bootcd.iso

rm -rf bootcd{,.iso}


3.3. 从硬盘分区启动

如果您碰巧丢失了可引导 CD,启动分区可能会派上用场。请记住,hda1 是可写介质,因此不安全;仅在紧急情况下使用它!

创建并挂载 ext2 文件系统

dd if=/dev/zero of=/dev/hda1 bs=8192
mke2fs /dev/hda1
mount /dev/hda1 /loader

复制内核和初始 ramdisk

cp /boot/{vmlinuz,initrd.gz} /loader

如果您使用 grub

mkdir /loader/boot
cp -av /boot/grub /loader/boot/
cat > /loader/boot/grub/menu.lst << EOF
default 0
timeout 10
color green/black light-green/black
title Linux
    root (hd0,0)
    kernel /vmlinuz ro root=/dev/ram0
    initrd /initrd.gz
EOF
grub-install --root-directory=/loader /dev/hda
umount /loader

如果您使用 lilo

mkdir /loader/{boot,dev,etc}
cp /boot/boot.b /loader/boot/
mknod -m 600 /loader/dev/hda  b 3 0
mknod -m 600 /loader/dev/hda1 b 3 1
mknod -m 600 /loader/dev/hda2 b 3 2
mknod -m 600 /loader/dev/hda3 b 3 3
mknod -m 600 /loader/dev/hda4 b 3 4
mknod -m 600 /loader/dev/ram0 b 1 0
cat > /loader/etc/lilo.conf << EOF
lba32
boot=/dev/hda
prompt
timeout=60
image=/vmlinuz
    label=Linux
    initrd=/initrd.gz
    read-only
    root=/dev/ram0
EOF
lilo -r /loader
umount /loader


4. 最后步骤

仍然在 chroot 中,修改 /etc/fstab,使其包含

/dev/loop0      /               ext3    defaults       0       1

删除 /etc/mtab 并退出 chroot。最后,运行 “umount -d /mnt/efs” 并重启。如果出现问题,您仍然可以通过在 LILO: 提示符下输入 “Linux root=/dev/hda3” 来启动未加密的分区。

如果一切顺利,您现在可以重新分区您的磁盘并加密 hda3 以及 hda4。在以下脚本中,我们假设 hda3 将保存交换设备,hda4 将包含 /home;您应该首先初始化这两个分区

shred -n 1 -v /dev/hda3
shred -n 1 -v /dev/hda4
losetup -e aes256 -S xxxxxx /dev/loop1 /dev/hda3
losetup -e aes256 -S xxxxxx /dev/loop2 /dev/hda4
mkswap /dev/loop1
mke2fs -j /dev/loop2

然后在系统启动目录中创建一个脚本并更新 fstab

cat > /etc/init.d/loop << "EOF"
#!/bin/sh

if [ "`/usr/bin/md5sum /dev/hda1`" != \
     "5671cebdb3bed87c3b3c345f0101d016  /dev/hda1" ]
then
    echo -n "WARNING! hda1 integrity verification FAILED - press enter."
    read
fi

echo "1st password chosen above" | \
    /sbin/losetup -p 0 -e aes256 -S xxxxxx /dev/loop1 /dev/hda3

echo "2nd password chosen above" | \
    /sbin/losetup -p 0 -e aes256 -S xxxxxx /dev/loop2 /dev/hda4

/sbin/swapon /dev/loop1

for i in `seq 0 63`
do
    echo -n -e "\33[10;10]\33[11;10]" > /dev/tty$i
done

EOF

chmod 700 /etc/init.d/loop
ln -s ../init.d/loop /etc/rcS.d/S00loop
vi /etc/fstab
...
/dev/loop2      /home           ext3    defaults       0       2


5. 关于本 HOWTO

加密根文件系统 HOWTO 最初于 2002 年 11 月为 Linux From Scratch 项目编写。我要感谢此后为本文档做出贡献的许多人(按时间倒序排列):Micha Borrmann、Dennis Lemckert、Oleg Vyushin、Ellen Bokhorst、Daczi L�szl�、Gaetano Zappulla、Guillaume Lehmann、Claude Thomassin、Jean-Philippe Gu�rard、Luc Vo Van、Jacobus Brink、Ernesto P�rez Est�vez、Matthew Ploessel、Mike Lorek、Lars Bungum、Michael Shields、Julien Perrot、Grant Stephenson、Cary W. Gilmer、James Howells、Pedro Baez、Josh Purinton、Jari Ruusu 和 Zibeli Aton。

本 HOWTO 已被翻译成多种语言

请将任何意见发送给 Christophe Devine