【问题标题】:How to load LUKS passphrase from USB, falling back to keyboard?如何从 USB 加载 LUKS 密码,回退到键盘?
【发布时间】:2013-11-11 21:29:50
【问题描述】:

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

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

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

  • 及时加载USB模块。

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

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

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

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

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

【问题讨论】:

    标签: linux encryption disk luks


    【解决方案1】:

    我的很多解决方案都来自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/&lt;ID&gt;

    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 时,它只是简单地运行,并且输出通过管道传送到luksOpen,没有其他检查。无法发出错误信号(USB 驱动器不存在)或回退到键盘输入。如果密码失败,keyscript 会在循环中再次运行,最多运行几次;但是我们没有被告知我们正在进行哪个迭代。此外,我们无法控制 keyscript 何时运行,因此我们无法确定 Linux 是否已识别 USB 驱动器。

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

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

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

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

      最终脚本:

      #!/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
      

    【讨论】:

    • 这可能是少数几个值得使用/dev/random 而不是/dev/urandom 的情况之一。
    • @SamuelEdwinWard - 来自 crypttab 手册页:'...如果系统没有足够的熵来生成真正随机的加密密钥,则使用 /dev/random 可能会阻止启动完成。'不过,为了增加安全性,使用 /dev/random 可能是值得的。
    • @Rondo,我认为这句话是在谈论每次启动时生成一个新的随机密钥。在这种情况下,密钥会在启动时间之前生成一次,所以这应该不是问题。最坏的情况是用户可以生成更多的熵,直到密钥完成。
    • @SamuelEdwinWard - 啊,真的。
    • 这个程序对我来说效果很好。我什至不必在 Debian Jessie 8.0 中使用这个 initramfs 东西(只要有一个 keyscript 就足够了)。
    【解决方案2】:

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

    【讨论】:

    • 最好直接给.sh文件的链接。
    【解决方案3】:

    尽管@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 只是默默地忽略了。所以我不知道发生了什么,直到我发现 this post。几乎所有关于 crypttab 设置的在线帖子都是针对 initramfs 而不是针对 systemd。所以我们需要将initramfs添加到crypttab中的所有条目以避免出现问题。

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

    @andrew 发布了一种在文件系统的原始区域中使用数据隐藏的好方法。但是,我发现当我们想要自动创建分区并将原始数据添加到大量 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/&lt;keyfile FS uuid&gt;:/&lt;keyfile path relative to usbkey root&gt;:&lt;timeout in sec&gt;

    #!/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 中的新参数:

    【讨论】:

      【解决方案4】:

      要附上上述优秀答案,请参阅可用于写入/生成和读取原始块设备密钥的 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 指南。

      crypto-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”编译,它就可以提供操作原始密钥内容的简单方法。

      readkey.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>)
      

      谢谢

      【讨论】:

        【解决方案5】:

        这里有一个类似于one by Andrew的解决方案,但是

        • 使用Debian crypttab man page 中描述的 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 是必需的,因为如果crypttab 中未提及passdev,则不会复制它。同样,manual_add_modules vfat 将确保仍然可以使用 vfat USB 磁盘。

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

        【讨论】:

          猜你喜欢
          • 2012-09-12
          • 1970-01-01
          • 2011-08-11
          • 1970-01-01
          • 2019-02-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-24
          相关资源
          最近更新 更多