17

我想设置一个具有全磁盘加密的无头 Linux (Debian Wheezy) PC,能够使用 USB 驱动器或通过键盘输入密码来解锁磁盘。我的起点是使用 Debian 安装程序中的基本全盘加密选项进行全新安装,它将 /boot 以外的所有内容作为 LUKS 加密的逻辑卷组进行管理,并为我提供键盘选项。我将在答案中描述我当前的解决方案,希望它有用并且其他人可以改进它。

以下是我遇到的一些问题:

  • 设置密码并将其放在 USB 驱动器上。

  • 及时加载 USB 模块。

  • 等待 USB 驱动器被 Linux 识别,然后再尝试读取它。

  • 识别正确的 USB 驱动器(不是碰巧插入的其他驱动器)。

  • 编写“keyscript”以从 USB 驱动器中提取密码。

  • 确保在所有 USB 故障情况下都回退到键盘。

我会接受一个有重大改进的答案,并赞成提供贡献的答案。

4

5 回答 5

26

我的很多解决方案都来自这篇文章,Using A USB Key For The LUKS Passphrase

  1. 创建一个随机密码:

    dd if=/dev/urandom bs=1 count=256 > passphrase
    
  2. 插入 USB 驱动器。 dmesg输出将显示设备名称;假设/dev/sdd。弄清楚它的大小:

    blockdev --getsize64 /dev/sdd
    
  3. 我决定在原始设备的末尾安装密码短语,认为它可能会在任何意外使用 USB 驱动器时幸存下来。

    dd if=passphrase of=/dev/sdd bs=1 seek=<size-256>
    
  4. 将密码添加到 LUKS 卷:

    cryptsetup luksAddKey /dev/sda5 passphrase
    

    这不会影响安装程序中现有的手动输入密码。可以删除密码短语文件:

    rm passphrase
    
  5. 为 USB 记忆棒找到一个唯一的名称,以便我们可以在存在时识别它:

    ls -l /dev/disk/by-id | grep -w sdd
    

    您应该看到一个符号链接。我会打电话/dev/disk/by-id/<ID>的。

  6. 编辑/etc/crypttab. 你应该看到如下一行:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 none luks
    

    将其修改为:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 /dev/disk/by-id/<ID> luks,keyscript=/bin/passphrase-from-usb
    
  7. 上面提到的keyscript将需要从 USB 设备中读取密码。然而,它需要做的还不止这些。要了解它的使用方式,请检查/usr/share/initramfs-tools/scripts/local-top/cryptroot在引导时运行以解锁根设备的脚本。请注意,当keyscript设置 a 时,它只是简单地运行,并且输出通过管道传输到luksOpen没有其他检查。无法发出错误信号(USB 驱动器不存在)或回退到键盘输入。如果密码失败,keyscript 会在循环中再次运行,最多运行几次;但是我们没有被告知我们正在进行哪个迭代。此外,我们无法控制 keyscript 何时运行,因此我们无法确定 Linux 是否已识别 USB 驱动器。

    我用一些技巧解决了这个问题:

    1. 轮询 USB 驱动器并等待 3 秒钟以使其出现。这对我有用,但我很想知道更好的方法。

    2. 在第一次运行时创建一个虚拟文件/passphrase-from-usb-tried,以表明我们至少运行过一次。

    3. 如果我们至少运行过一次,或者找不到 USB 驱动器,请运行用于键盘输入的askpass程序。cryptroot

    最终脚本:

    #!/bin/sh
    
    set -e
    
    if ! [ -e /passphrase-from-usb-tried ]; then
        touch /passphrase-from-usb-tried
        if ! [ -e "$CRYPTTAB_KEY" ]; then
            echo "Waiting for USB stick to be recognized..." >&2
            sleep 3
        fi
        if [ -e "$CRYPTTAB_KEY" ]; then
            echo "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) from USB key" >&2
            dd if="$CRYPTTAB_KEY" bs=1 skip=129498880 count=256 2>/dev/null
            exit
        else
            echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
        fi
    fi
    
    /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)\nEnter passphrase: "
    

    最后,我们需要确保该脚本在 initramfs 中可用。创建/etc/initramfs-tools/hooks/passphrase-from-usb包含:

    #!/bin/sh
    
    PREREQ=""
    
    prereqs() {
            echo "$PREREQ"
    }
    
    case "$1" in
            prereqs)
                    prereqs
                    exit 0
            ;;
    esac
    
    . "${CONFDIR}/initramfs.conf"
    . /usr/share/initramfs-tools/hook-functions
    
    copy_exec /bin/passphrase-from-usb /bin
    
  8. 我的 initramfs 中没有 USB 驱动程序。(似乎它们在 Debian 的更高版本中是默认的。)我必须通过添加来添加它们/etc/initramfs-tools/modules

    uhci_hcd
    ehci_hcd
    usb_storage
    
  9. 完成后,更新 initramfs:

    update-initramfs -u
    
于 2013-10-31T18:21:49.953 回答
5

如果我可以简单地拥有一个包含可以解锁磁盘的密码的小型 USB 记忆棒,那对我来说将是理想的选择。这不仅对服务器很方便(您可以将 U 盘留在服务器中 - 目标是能够返回损坏的硬盘而不必担心机密数据),它对我的​​笔记本电脑也很有用:插入启动时使用 U 盘,解锁加密磁盘后将其移除。

我现在编写了一个补丁,它将在所有设备的根目录中搜索文件“cryptkey.txt”并尝试使用每一行作为密钥进行解密。如果失败:恢复输入密码短语。

这确实意味着密钥不能包含 \n,但这也适用于任何键入的密钥。好处是您可以使用同一个 U 盘为多台机器存储密钥:您不需要为每台机器使用单独的 U 盘。因此,如果您的物理密钥环中有一个 USB 驱动器,您可以在物理上关闭时为您启动的所有计算机使用相同的驱动器。

您使用以下命令添加密钥:

cryptsetup luksAddKey /dev/sda5

然后将相同的密钥作为一行放入 USB/MMC 磁盘上名为“cryptkey.txt”的文件中。补丁在这里:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864647

如果您的 initramfs 中不存在 USB 驱动程序、MMC 驱动程序或文件系统,您需要通过添加到 /etc/initramfs-tools/modules 来添加它们:

uhci_hcd
ehci_hcd
usb_storage
nls_utf8
nls_cp437
vfat
fat
sd_mod
mmc_block
tifm_sd
tifm_core
mmc_core
tifm_7xx1
sdhci
sdhci_pci

完成后,更新 initramfs:

update-initramfs -u

它可以作为补丁和文件在以下位置找到:https ://gitlab.com/ole.tange/tangetools/tree/master/decrypt-root-with-usb

于 2014-05-04T02:06:40.323 回答
2

尽管@Andrew 给出了很好的答案,它在以前的版本中有效。该解决方案实际上已经过时,需要针对 ubuntu 18.04 和 19.10 进行大量调整。所以我想分享我对此的研究。

关于 crypttab 有几个问题。从 14.04 到 18.04 再到 19.10,sepcs 实际上发生了很大变化。它开始支持 cryptsetup 的更多参数。例如 keyfile-offset、keyfile-size 等。一些选项(例如 nobootwait)已经消失。其他发行版已支持某些参数,但 ubuntu 尚不支持(例如非常好的参数 keyfile-timeout。这可以消除整个 keyscript,因为它会在 keyfile-timeout 后自动回退到键盘输入。)

ubuntu 上 crypttab 的主要缺陷是它实际上由 2 个不同的进程处理。一个是传统的 initramfs,另一个是现代的 systemd。Systemd 应该在许多方面更加先进和灵活。然而,systemd 对 crypptab 的支持很差,有很多选项,比如 keyscript 只是默默地忽略了。所以我不知道发生了什么,直到我发现了这篇文章。几乎所有关于 crypttab 设置的在线帖子都是针对 initramfs 而不是针对 systemd。所以我们需要添加initramfs到crypttab中的所有条目以避免出现问题。

我还发现了一种在没有 VM 或重复重启的情况下调试我们的 keyscript 和 crypttab 的好方法。它是cryptdisks_start。在我们实际将更改传播到 initramfs 之前,我们应该始终使用这个不错的命令对其进行测试。否则,您最终将被锁定在您的系统之外,并且只能通过 chroot 环境来恢复它。

@andrew 发布了一种在文件系统的原始区域中使用数据隐藏的好方法。但是,当我们想要自动创建分区并将原始数据 dd 到大量 usbkey 时,我发现这很烦人,我们必须计算所有不同文件系统和不同分区大小的偏移量。此外,如果用户不小心写入 FS,则存在密钥被覆盖的风险。在这种情况下,没有任何 FS 的原始分区更有意义。但是原始分区没有 UUID,这对于自动解锁不是很有用。因此,我想介绍一种只在 usbkey 文件系统上使用普通密码短语文件的方法。passdev 的主要问题是它在读取文件期间不查找/停止。因此,当我们想要回退到键盘输入时,我们不能使用 keyfile-offset 和 keyfile-size 选项。因为 cryptsetup 实际上会尝试跳过输入内容,如果内容短于 keyfile-size,则会引发错误。这也意味着如果偏移量很大,passdev 可能会非常慢,因为它总是从头开始读取。但是,没有必要为文件系统上的实际文件实现偏移量和密钥文件大小。我相信这些是为原始设备创建的。

密码表

luks-part UUID="<uuid>" /dev/disk/by-uuid/<keyfile FS uuid>:/<keyfile path relative to usbkey root>:<timeout in sec> luks,keyfile-offset=<seek to the key>,keyfile-size=<>,keyscript=/bin/passphrase-from-usbfs.sh,tries=<number of times to try>,initramfs

keyscript passphrase-from-usbfs.sh 利用/lib/cryptsetup/scripts/passdev它将等待 USB 设备并挂载 fs,然后通过管道输出文件内容。它支持CRYPTTAB_KEY./device-path/<keyfile FS uuid>:/<keyfile path relative to usbkey root>:<timeout in sec>

#!/bin/sh
#all message need to echo to stderr, the stdout is used for passphrase
# TODO: we may need to do something about the plymouth
echo "CRYPTTAB_KEY=$CRYPTTAB_KEY" >&2
echo "CRYPTTAB_OPTION_keyfile_offset=$CRYPTTAB_OPTION_keyfile_offset" >&2
#set your offset and file size here if your system does not support those paramters
#CRYPTTAB_OPTION_keyfile_offset=
#CRYPTTAB_OPTION_keyfile_size=
echo "timeout=$CRYPTTAB_OPTION_keyfile_timeout" >&2
CRYPTTAB_OPTION_keyfile_timeout=10 # keyfile-timeout is not supported yet 
pass=$(/lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY)
rc=$?
if ! [ $rc -eq 0 ]; then
    echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
    /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) Enter passphrase: "
else
    echo "successfully load passphrase." >&2
    echo -n $pass
fi

钩子告诉 update-initramfs 复制我们的脚本。

#!/bin/sh

PREREQ=""

prereqs() {
        echo "$PREREQ"
}

case "$1" in
        prereqs)
                prereqs
                exit 0
        ;;
esac

. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions
copy_exec /bin/passphrase-from-usbfs.sh
copy_exec /bin/passphrase-from-usb.sh
#when using passdev we need to hook additionaly FS and binary
copy_exec /lib/cryptsetup/scripts/passdev
manual_add_modules ext4 ext3 ext2 vfat btrfs reiserfs xfs jfs ntfs iso9660 udf

最后,我发布了 passphrase-from-usb.sh 的更新版本,它可以使用 crypttab 中的新参数:

于 2019-10-29T11:13:19.183 回答
1

为了配合上面的优秀答案,请参阅可用于编写/生成和读取原始块设备密钥的 C 例程。“readkey.c”从块设备中提取给定大小的密钥,“writekey.c”可以生成或写入现有密钥到原始设备。编译后的“readkey.c”可以在自定义脚本中使用,以从原始块设备中提取已知大小的密钥,如下所示:

readkey </path/to/device> <keysize>

要查看“writekey”的用法,编译后不带标志运行它。
要编译只需使用:

gcc readkey.c -o readkey

gcc writekey.c -o writekey

我在 Verbatim 16GB USB 2.0 USB 闪存驱动器上进行了测试,并在下面发布了 crypttab 中的自定义“keyscript=”。“crypto-usb.sh”的想法来自“debian etch”cryptsetup 指南。

加密usb.sh

#!/bin/sh
echo ">>> Trying to get the key from agreed space <<<" >&2
modprobe usb-storage >/dev/null 2>&1
sleep 4
OPENED=0
disk="/sys/block/sdb"
boot_dir="/boot"
readkey="/boot/key/readkey"
echo ">>> Trying device: $disk <<<" >&2
F=$disk/dev
if [ 0`cat $disk/removable` -eq 1 -a -f $F ]; then
    mkdir -p $boot_dir
    mount /dev/sda1 $boot_dir -t ext2 >&2
    echo ">>> Attempting key extraction <<<" >&2
    if [ -f $readkey ]; then
        # prints key array to the caller
        $readkey /dev/sdb 4096
        OPENED=1
    fi
    umount $boot_dir >&2
fi


if [ $OPENED -eq 0 ]; then
    echo "!!! FAILED to find suitable key !!!" >&2
    echo -n ">>> Try to enter your password: " >&2
    read -s -r A
    echo -n "$A"
else
    echo ">>> Success loading key <<<" >&2
fi

生成密钥时必须提供密钥大小,生成的密钥会保存到“.tmpckey”文件中,文件权限为 0600,以备后用。写入现有密钥时,大小是通过测量现有密钥大小来确定的。这看起来很复杂,但是一旦用简单的“gcc”编译,它就可以提供操作原始密钥内容的简单方法。

读键.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(int argc, char *argv[])
{
    int blockSize = 512;
    int keySize = 2048; 

    FILE *device;       

    if (  argc == 3 
           && (sizeof(argv[1]) / sizeof(char)) > 1
           && (sizeof(argv[2]) / sizeof(char)) > 1
       && (atoi(argv[2]) % 512) == 0
       ) {
        device = fopen(argv[1], "r");
        if(device == NULL) { 
            printf("\nI got trouble opening the device %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }
        keySize = atoi(argv[2]);        
    }
    else if (  argc == 2 
            && (sizeof(argv[1]) / sizeof(char)) > 1
        ) {
        device = fopen(argv[1], "r");
        if(device == NULL) { 
            printf("\nI got trouble opening the device %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }

    }
    else {

        printf("\nUsage: \n");
        printf("\nKey Size Provided: \n");
        printf("\n\t\treadkey </path/to/device> <keysize> \n");
        printf("\nDefault key size: %d\n", keySize);
        printf("\n\t\treadkey </path/to/device>\n");
        exit(1);
    }

    int count;

    char *block;

    /* Verify if key is multiple of blocks */
    int numBlocks = 0;
    if (keySize % 512 != 0) {
       printf("\nSory but key size is not multiple of block size, try again. TA.\n");
       exit(1);
    }

    /* Seek till the end to get disk size and position to start */
    fseek(device, 0, SEEK_END);

    /* Determine where is the end */
    long endOfDisk = ftell(device);

    /* Make sure we start again */
    rewind(device); // Do I need it ???

    /* Get the required amount minus block size */
    long startFrom = endOfDisk - blockSize - keySize;

    /* Allocate space for bloc */
    block = calloc(keySize, sizeof(char));

    /* Start reading from specified block */
    fseek(device, startFrom, SEEK_SET);
    fread(block, 1, keySize, device);

    /* Do something with the data */
    for(count = 0; count < keySize/*sizeof(block)*/; count++){
        printf("%c", block[count]);
    }

    /* Close file */
    fclose(device);

    /* Make sure freed array is zeroed */
    memset(block, 0, keySize);
    free(block);
}

writekey.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int blockSize = 512;
    int keySize = 2048;

    int count;

    unsigned char *block;

    /*
        Thing to always remember that argv starts from 0 - the name of the program, and argc starts from 1 i.e. 1 is the name of the program.
    */
    if ( argc == 3 
       && strcmp(argv[1], "genwrite") != 0
       && (sizeof(argv[2]) / sizeof(char)) > 2
       ) {
        char ch;
        FILE *keyF;
        keyF = fopen(argv[1], "r");
        if (keyF == NULL) exit(EXIT_FAILURE);

        /* Tell key Size */
        fseek(keyF, 0, SEEK_END);
        keySize = ftell(keyF);
        rewind(keyF);
        printf("\nKey Size: %d\n", keySize);

        block = calloc(keySize, sizeof(char));
        printf("\n-- Start Key --:\n");
                for(count = 0; count < keySize/*sizeof(block)*/; count++){
            char ch = fgetc(keyF);
                        block[count] = ch;
            /*
              Uncomment below to see your key on screen
            */
            // printf("%c",ch);

                }
        printf("\n-- End Key --:\n");
        fclose(keyF);
    }
    else if (  argc == 3 
        && strcmp(argv[1], "genwrite") == 0 
        && (sizeof(argv[2]) / sizeof(char)) > 2
        ) 
        {
        printf("\n-- Attempting to create random key(ish --) of size: %d\n", keySize);
        block = calloc(keySize, sizeof(char));
        int count;
        for(count = 0; count < keySize/*sizeof(block)*/; count++){
            block[count] = (char) rand();
        }
        FILE *tmpfile;
        tmpfile = fopen(".tmpckey", "w");
        if(tmpfile == NULL) exit(EXIT_FAILURE);
        fwrite(block, 1, keySize, tmpfile);
        fclose(tmpfile);
        chmod(".tmpckey", 0600);
    }
    else if (  argc == 4 
        && strcmp(argv[1], "genwrite") == 0
        && (sizeof(argv[2]) / sizeof(char)) > 2
        && ((atoi(argv[3]) % 512) == 0)
        ) 
        {
        keySize = atoi(argv[3]);
        printf("\n-- Attempting to create random key(ish --) of size: %d\n", keySize);
        block = calloc(keySize, sizeof(char));
        int count;
        for(count = 0; count < keySize/*sizeof(block)*/; count++){
            block[count] = (char) rand();
        }
        FILE *tmpfile;
        tmpfile = fopen(".tmpckey", "w");
        if(tmpfile == NULL) exit(EXIT_FAILURE);
        fwrite(block, 1, keySize, tmpfile);
        fclose(tmpfile);
        chmod(".tmpckey", 0600);
    }   
    else {
        printf("\n");
        printf("################################################################################\n");
        printf("#                                                                              #\n");
        printf("#                              Usage:                                          #\n");
        printf("#                                                                              #\n");
        printf("################################################################################\n");
        printf("#> To write existing key to device:                                            #\n");
        printf("#                                                                              #\n");
        printf("#     writekey </path/to/keyfile> </path/to/removable/sd*>                     #\n");
        printf("#                                                                              #\n");
        printf("#> To generate and write pseudo random key,                                    #\n");
        printf("#> key will be saved to temporary file .tmpckey                                #\n");
        printf("#                                                                              #\n");
        printf("#     writekey genwrite </path/to/removable/sd*> <keysize in multiples of 512> #\n");
        printf("#                                                                              #\n");
        printf("#> When keysize is not provided default size is set to %d.                     #\n", keySize);
        printf("#                                                                              #\n");
        printf("################################################################################\n");
        exit(1);
    }

    /*
        Some printf debugging below, uncomment when needed to see what is going on.
    */
    /*
    printf("\nNumber of Args: %d\n", argc);
    printf("\nCurrently block array contains: \n");
    for(count = 0; count < keySize; count++){
        printf("%c", block[count]);
    }
    printf("\n-- End block -- \n");
    */
    /* Open Device itp... */
    FILE *device = fopen(argv[2], "a");
    if(device == NULL) exit(EXIT_FAILURE);

    printf("\nDevice to write: %s\n", argv[2]);

    fseek(device, 0, SEEK_END);

    /* Determine where is the end */
    long endOfDisk = ftell(device);
    printf("\nDevice Size: %ld\n", endOfDisk);

    /* Verify if key is multiple of blocks */
    int numBlocks = 0;
    if (keySize % 512 != 0 || endOfDisk < (blockSize + keySize) ) {
            printf("\nSorry but key size is not multiple of block size or device you trying to write to is too small, try again. TA.\n");
        fclose(device);
            exit(1);
    }



    /* Make sure we start again */
    rewind(device);

    /* Get the required amount sunbstracting block size */
    long startFrom = endOfDisk - blockSize - keySize;

    /* Write some data to the disk */
    printf("\nWriting data starting from: %ld\n", startFrom);
    fseek(device, startFrom, SEEK_SET);
    fwrite(block, 1, keySize, device);
    printf("\nBlock Position after data write procedure : %ld\n", ftell(device));

    /*
        Below is just for convenience, to read what was written,
        can aid in debugging hence left commented for later.
    */
    /*
    printf("\nAmount of Data written : %ld\n", ftell(device) - startFrom);

    // Start reading from specified block 
    printf("\n>>>>>>>> DEBUGGING SECTION <<<<<<<<<\n");
    rewind(device); //
    fseek(device, startFrom, SEEK_SET);
    printf("\nBlock Position before read attempted: %d\n", ftell(device));
    printf("\nKey size: %d\n", keySize);
    fread(block, 1, keySize, device);

    // Do something with the data
    printf("\nBlock Position startFrom: %ld\n", startFrom);
    printf("\nBlock Position after read: %d\n", ftell(device));
    printf("\n-- Buffer Read: --\n");
    for(count = 0; count < keySize; count++){
        printf("%c", block[count]);
    }
    printf("\n-- End block -- \n");
    printf("\n--  -- \n");
    printf("\n--  -- \n");
    */

    /* Close file */
    fclose(device);

    /* Make sure freed array is zeroed */
    memset(block, 0, keySize);
    free(block);

/* Return success, might change it to be useful return not place holder */
return 0;
}

验证写入原始设备的密钥与文件中的密钥相同(如果密钥相同,下面将不输出任何内容):

diff -B <(./readkey </path/to/device> 4096) <(cat .tmpckey)

或者对于使用自己的方式生成的现有密钥:

diff -B <(./readkey </path/to/device> <generated elsewhere key size>) <(cat </path/to/keyfile>)

谢谢你

于 2016-06-24T08:43:16.190 回答
1

这是一个类似于Andrew的解决方案,但是

  • 使用Debian crypttab 手册页中描述的 CRYPTTAB_TRIED来区分尝试,以及

  • 在第一次尝试时调用现有的标准 keyscript /lib/cryptsetup/scripts/passdev

  1. 像往常一样为passdev脚本创建密钥文件或密钥分区。

  2. 创建以下文件/usr/local/bin/key-from-usb并使其可执行。

    #!/bin/sh
    set -e
    if [ $CRYPTTAB_TRIED -ge 1 ]; then
      /lib/cryptsetup/askpass "Second try to unlock $CRYPTTAB_SOURCE ($CRYPTTAB_NAME). Please enter passphrase: "
    else
      /lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY
    fi
    
  3. /etc/crypttab使用参数keyscript=/usr/local/bin/key-from-usb

  4. /etc/initramfs-tools/hooks/key-from-usb使用此内容创建:

    #!/bin/sh
    
    PREREQ=""
    
    prereqs() {
            echo "$PREREQ"
    }
    
    case "$1" in
             prereqs)
                     prereqs
                     exit 0
             ;;
    esac
    
    . "${CONFDIR}/initramfs.conf"
    . /usr/share/initramfs-tools/hook-functions
    
    manual_add_modules vfat
    
    copy_exec /usr/lib/cryptsetup/scripts/passdev /usr/lib/cryptsetup/scripts/passdev
    
    copy_exec /usr/local/bin/key-from-usb /usr/local/bin/key-from-usb
    

    这里的第一copy_exec行是必需的,因为passdev如果没有在crypttab. 同样,manual_add_modules vfat将确保仍然可以使用 vfat USB 磁盘。

提示:使用lsinitramfs /boot/initrd.img-...并比较/比较结果以检查是否包含脚本及其所有依赖项。

于 2020-12-31T15:30:47.007 回答