背景

同样的,在进行了全盘加密后每次boot都需要输入密钥对根目录进行解密,久而久之就会觉得挺麻烦的。在Windows下使用的BitLocker对系统盘进行加密,密钥正是存储在TPM芯片中的,看到Linux内核对TPM2是支持,于是就想将手动输入密钥这一步省略去,从TPM芯片读取进行解密。

开始

准备

在之前的文章中应当是实现了LUKS的全盘加密,顺着走。

首先需要基本管理tpm的软件,在Arch中,安装即可

$ yay -Syu tpm2-abrmd tpm2-tools tpm2-tss

测试TPM是否工作良好,读取存储在TPM中的PCR值

$ tpm2_pcrread
sha1:
  0 : 0xA32203D76D2FD203DD76D2FD203D76D21D2C99A8
  1 : 0x55CB0B4841FECB0B44841FECB0B4841F9CB64433
  2 : 0xB2AFC31EA95BDFC311EA95BDFC31EA955DFD7236
  3 : 0xB2AFC31EA95BDFC311EA95BDFC31EA955DFD7236
  4 : 0x123B07B3F93E6B07BB3F93E6B07B3F93E6B9C5B7
  5 : 0x5F294992FB8CB949992FB8CB94992FB8CB9561B1
  6 : 0xB2AFC31EA95BDFC311EA95BDFC31EA955DFD7236
  7 : 0xE6CEDBCFC7381EDBCCFC7381EDBCFC7331ED2059
  8 : 0x0000000000000000000000000000000000000000
  9 : 0x0000000000000000000000000000000000000000
  10: 0x0000000000000000000000000000000000000000
  11: 0x0000000000000000000000000000000000000000
  12: 0x0000000000000000000000000000000000000000
  13: 0x0000000000000000000000000000000000000000
  14: 0x0000000000000000000000000000000000000000
  15: 0x0000000000000000000000000000000000000000
  16: 0x0000000000000000000000000000000000000000
  17: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  18: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  19: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  20: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  21: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  22: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  23: 0x0000000000000000000000000000000000000000
sha256:
  0 : 0x46D108639A20A20B0E15A495B3329C85639A20A20B0E15A495B3329C85BF81DA
  1 : 0xE40B13F59B29B2999514F8C32835BEEBF59B29B2999514F8C32835BEEB784292
  2 : 0x3D458CFE55CC5CC03EA1F443F114A9FCFE55CC5CC03EA1F443F114A9FC8E7969
  3 : 0x3D458CFE55CC5CC03EA1F443F114A9FCFE55CC5CC03EA1F443F114A9FC8E7969
  4 : 0x2008CC50255C55C3F518AF21A8D0751D50255C55C3F518AF21A8D0751DD3499A
  5 : 0x74572C5B1D49D49B433314DBEFE938FF5B1D49D49B433314DBEFE938FF637DC0
  6 : 0x3D458CFE55CC5CC03EA1F443F114A9FCFE55CC5CC03EA1F443F114A9FC8E7969
  7 : 0xBCC172045B8CB8C4C81F621F40C486D7045B8CB8C4C81F621F40C486D796E02D
  8 : 0x0000000000000000000000000000000000000000000000000000000000000000
  9 : 0x0000000000000000000000000000000000000000000000000000000000000000
  10: 0x0000000000000000000000000000000000000000000000000000000000000000
  11: 0x0000000000000000000000000000000000000000000000000000000000000000
  12: 0x0000000000000000000000000000000000000000000000000000000000000000
  13: 0x0000000000000000000000000000000000000000000000000000000000000000
  14: 0x0000000000000000000000000000000000000000000000000000000000000000
  15: 0x0000000000000000000000000000000000000000000000000000000000000000
  16: 0x0000000000000000000000000000000000000000000000000000000000000000
  17: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  18: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  19: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  20: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  21: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  22: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  23: 0x0000000000000000000000000000000000000000000000000000000000000000

至于其中每个值的含义,这里有一张图,可以看看

UEFI’s TPM

含义尚未弄清楚但是偶只知道说存储在一个位置即可,没有其他东西来更改的这个值的,如果你不是Windows的话,从含义可以看出应当是不会影响的。

写入TPM

将密钥写入到TPM2芯片,假设你解密密钥存储的位置是/usr/_crypto_keyfile

一个小问题是密钥的长度,太长了不得行,这个issue指出,长度应该是128淦。

# 清除TPM芯片
tpm2_evictcontrol -C o -c 0x81000000
# 写入密钥
# 这里只用了PCR0和7,PCR4听说是系统生成的,每次内核的更改都需要重新写入一遍密钥
tpm2_createpolicy --policy-pcr -l sha1:0,7 -L policy.digest
tpm2_createprimary -C e -g sha1 -G rsa -c primary.context
tpm2_create -g sha256 -u obj.pub -r obj.priv -C primary.context -L policy.digest -a "noda|adminwithpolicy|fixedparent|fixedtpm" -i /usr/_crypto_keyfile
tpm2_load -C primary.context -u obj.pub -r obj.priv -c load.context
tpm2_evictcontrol -C o -c load.context 0x81000000
rm load.context obj.priv obj.pub policy.digest primary.context

完成过后,你可以使用如下命令将TPM中的密钥取出,和原来的密钥进行比较

tpm2_unseal -c 0x81000000 -p pcr:sha1:0,7 -o /crypto_keyfile.bin
# 记住这个输出路径

更改内核

首先呢参照大佬的脚本再更改一下下,原因为不知道大佬的mkinitcpio.conf是怎么写的,这里摸索了下。

# /etc/initcpio/hooks/encrypt-tpm
#!/usr/bin/bash

run_hook() {
    modprobe -a -q tpm >/dev/null 2>&1
    modprobe -a -q tpm_crb >/dev/null 2>&1
    modprobe -a -q tpm_tis >/dev/null 2>&1
    modprobe -a -q tpm_tis_core >/dev/null 2>&1
    modprobe -a -q trusted >/dev/null 2>&1
    tpm2_unseal -c 0x81000000 -p pcr:sha1:0,7 -o /crypto_keyfile.bin
}
# /etc/initcpio/install/encrypt-tpm
#!/bin/bash

build() {
    local mod

    add_module "tpm"
    add_module "tpm_crb"
    add_module "tpm_tis"
    add_module "tpm_tis_core"
    add_module "trusted"

    add_binary "tpm2_unseal"
    add_binary "/usr/lib/libtss2-tcti-device.so"

    add_runscript
}

help() {
    cat <<HELPEOF
This hook allows for reading the encryption key from TPM.
HELPEOF
}

重点来了,上述两个script添加了HOOK动作,在生成内核的时候会被写入进去。下述是节选的关键配置,MODULES中已知的一定要有tpm_tis这个模块,否则在BOOT阶段内核中是没有TPM驱动的,偶把他们都加上了。

另外,BINARIES是上述script中需要使用的,FILES是后面解密LUKS驱动器所需要的 密钥的文件路径,这里的这个路径是默认的密钥的位置,当然也是可以指定的,但是这个根下面的东西在解密后就看不见了,因为解密后的会挂载到根目录,详见Wiki

# /etc/mkinitcpio.conf
MODULES=(vfat ext4 tpm tpm_crb tpm_tis tpm_tis_core trusted)
BINARIES=(tpm2_unseal /usr/lib/libtss2-tcti-device.so)
FILES=(/crypto_keyfile.bin)
HOOKS=(base udev autodetect modconf block filesystems keyboard fsck keymap encrypt-tpm encrypt )

随后重新生成内核,更新grub

#!/bin/bash
mkinitcpio -P

# 根据自己的路径哈
objcopy \
    --add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=0x20000 \
    --add-section .cmdline="/proc/cmdline" --change-section-vma .cmdline=0x30000 \
    --add-section .linux="/boot/vmlinuz-linux" --change-section-vma .linux=0x40000 \
    --add-section .initrd="/boot/initramfs-linux.img" --change-section-vma .initrd=0x3000000 \
    "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" "/boot/EFI/Archman/grubx64.efi"

grub-mkconfig -o /boot/grub/grub.cfg

可以先试一下,不得行重新写入密钥到TPM。

致谢

感谢大佬们,另外grub好像支持luks2的加密了,不用boot不加密啦。

噢对了,我没有对SecureBoot进行操作,这样还不错。

Full Disk Encryption on Arch Linux backed by TPM 2.0

Configuring Secure Boot + TPM 2