Ubuntu 20.04 and TPM2 encrypted system disk

Following the conversation around a past post about Ubuntu 18.04 and TPM2 encrypted system disk (can be found here), I have added a post about using a more modern Ubuntu (20.04) with TPM2. This post includes all the updates (many thanks to the commenter kelderek for setting up a very well working setup!) and has just been tested on a virtual Ubuntu with (virtual) TPM2 device. A note about how to get this setup – sometime in the future.

A very important note, before we begin – This is not enough! To fully prevent your data from being stolen by a bad person with a screwdriver, you will need to add some additional measures, like locking up your BIOS with a password (resetting the BIOS password resets TPM2 data, which is good) ; Signing and using your own embedded GRUB2 (which is not covered here, and maybe one day will be), with your own certificate ; Protect GRUB2 from booth changed using password ; Lock down boot devices in the BIOS (so the evil hacker cannot boot from a USB or CDROM without unlocking the BIOS first) ; Lock the hard drive (or SSD, or NVME) with a security to the BIOS (possible on some models of laptops and hard drives). All these steps are required to complete the security process in order to make the life of a cracker/hacker harder to the point of impossible, when attempting to obtain your data. Without them, the effort is great, but not impossible.
Also note that all the above described actions might lock you out of your own system in case of any hardware failure or forgotten password, so make sure you have a (secure!) backup of your data, or else…

Now – to the process. The idea is this: We add a new key to the cryptsetup – a long one, and this key is stored in TPM2. We add scripts which pull this key out of TPM2 store whenever the system boots. Thanks to some additional comments by Kelderek, we also add some failback, in case of an incorrect key, to allow up to recover and boot using manual key.

I will not wrap all my actions with ‘sudo’ command. All commands need to be called as root, so you can prefix this guide with ‘sudo -s’ or ‘sudo bash’ if you like. I can also assume you ‘cd’ to the root’s directory to protect the root.key file while it is still there. So – ‘sudo’ yourselves, and let’s begin.

Install required packages:

apt install tpm2-tools

Define TPM2 memory space to hold the key:

tpm2_nvdefine -s 64 0x1500016
# This command will define a 64 byte memory space in TPM2, at the above mentioned address

Create a random 64 byte key file:

cat /dev/urandom | tr -dc ‘a-zA-Z0-9’ | head -c 64 > root.key

Save the contents of the key file to TPM2:

tpm2_nvwrite -i root.key 0x1500016

Compare the contents of the TPM and the file, to verify that they are exactly the same:

echo root.key file contents: `cat root.key`
echo The value stored in TPM: `tpm2_nvread 0x1500016`

Identify the encrypted device, and add the key to the LUKS:

lsblk # Identify the owner of 'crypt'. We will assume it is /dev/sda3 in our example
cryptsetup luksAddKey /dev/sda3 root.key

Create a script to pull the key from TPM2:

if [ -f ".tpm2-getkey.tmp" ]; then
# tmp file exists, meaning we tried the TPM this boot, but it didn’t work for the drive and this must be the second
# or later pass for the drive. Either the TPM is failed/missing, or has the wrong key stored in it.
/lib/cryptsetup/askpass "Automatic disk unlock via TPM failed for  () Enter passphrase: "
# No tmp, so it is the first time trying the script. Create a tmp file and try the TPM
touch .tpm2-getkey.tmp
tpm2_nvread 0x1500016

This script will be embedded into the future initramfs (or initrd), and will pull the key from TPM2. Now, we need to set its permissions and ownerships:

chown root: /usr/local/sbin/tpm2-getkey
chmod 750 /usr/local/sbin/tpm2-getkey

Create a hook script to initramfs:

cat << EOF > /etc/initramfs-tools/hooks/tpm2-decryptkey
echo ""
case \$1 in
exit 0
. /usr/share/initramfs-tools/hook-functions
copy_exec `which tpm2_nvread`
copy_exec /usr/lib/x86_64-linux-gnu/libtss2-tcti-device.so.0.0.0
copy_exec /usr/lib/x86_64-linux-gnu/libtss2-tcti-device.so.0
copy_exec /lib/cryptsetup/askpass
exit 0

Set file permissions:

chown root: /etc/initramfs-tools/hooks/tpm2-decryptkey
chmod 755 /etc/initramfs-tools/hooks/tpm2-decryptkey

Edit crypttab:

The file /etc/crypttab needs to have an entry added at the end of the line containing the boot volume. For example (taken from the previous post’s comments):

sda3_crypt UUID=d4a5a9a4-a2da-4c2e-a24c-1c1f764a66d2 none luks,discard

should become:

sda3_crypt UUID=d4a5a9a4-a2da-4c2e-a24c-1c1f764a66d2 none luks,discard,keyscript=/usr/local/sbin/tpm2-getkey

First – backup your existing crypttab file:

cp /etc/crypttab /etc/crypttab.backup

If you have a single line in the file (only the boot volume is encrypted), you can use the following command:

sed -i 's%$%,keyscript=/usr/local/sbin/tpm2-getkey%' /etc/crypttab

Otherwise, you will have to append it manually.

Backup the original initrd and create a new one

cp /boot/initrd.img-$(uname -r) /boot/initrd.img-$(uname -r).orig
mkinitramfs -o /boot/initrd.img-$(uname -r) $(uname -r)


If all works well – you can now delete the file root.key holding a clear text key. You will still have your original manually defined decryption key working, and the initrd will fail-over to handle manual askpass if the automatic TPM2 fails to work, so you should be rather safe there, as well as update-proof.


  • The procedure might work on older Ubuntu systems, although it was not tested. A comment in the previous post suggested that the addition of the source
    deb http://cz.archive.ubuntu.com/ubuntu focal main universe
    to your Ubuntu 18.04, the same procedure should work. I did not test it yet.
  • The security of the system is not complete until you handle the other tasks mentioned at the beginning of the text.
  • This procedure does not cover TPM1.2 systems, and will not work without modification on them. I might document such process in the future.

Good luck, and post here if it works for you, or if you have any suggestions!

Tags: , ,

30 Responses to “Ubuntu 20.04 and TPM2 encrypted system disk”

  1. Running Systems » Blog Archive » Ubuntu 18.04 and TPM2 encrypted system disk Says:

    […] *** EDIT *** : An updated version of this post can be found here: https://run.tournament.org.il/ubuntu-20-04-and-tpm2-encrypted-system-disk/ […]

  2. Gabor Says:

    Couple of syntactical corrections:
    – tpm2_nvdefine is missing the underline
    – “uname -r” should be surrounded by backquote
    – in the line “cat << EOF" EOF should be surrounded by apostrophes, or else "$1" in line 8 will be evaluated immediately

  3. etzion Says:

    Thank you for your review. I have corrected these errors in the text. Unfortunately, sometimes, script lines get sanitised in WordPress…
    I have encapsulated the ‘uname -r’ with $( ) signs, fixed the underline, and escaped the dollar signs in cat << EOF blocks, so it should be fine now. Thanks for your input!

  4. JD Says:

    Thank you so much for this article !
    Had trouble setting up tpm2 before and this work like a charm !

  5. etzion Says:

    I am happy that it worked well for you!

  6. David Go Says:

    I just wanted to say thank you! This worked a treat, and saved me a lot of fiddling on my Dell 2-in-1.

    (I hacked something similar using TPS 1.2 on my old Dell Venue 11 Pro with Ubuntu 16.04 , but the new laptop does not support tpm 1. – and I did not know about/have the keyscript option then! ) The beauty of doing things this way is that I one can make use of the on-screen keyboard to enter a password to unlock the computer and bypass the need to have a keyboard plugged in to decrypt the hard drive.

  7. lamhoangtung Says:

    Thanks for the amazing writeup!

    Just some quick question:
    1. Is 0x1500016 the only option, can I use something else ? And how to choose something else ?
    2. Suppose that I want to reinstall everything with a new key, what should I run to delete they key from the TPM (at 0x1500016) ?
    3. If somehow the attacker can boot with another drive and run `tpm2_nvread 0x1500016`. Can they see the key that I have set ? If I can use other address, they can do a brute force right ?

  8. etzion Says:

    1. You can use different address spaces. Try and see.
    2. You don’t need to delete the key (although, you can) – you can reset the NV either from the BIOS, or from tpm2_nvundefine command, or you can (try) and skip the nvdefine in the 2nd run and just use nvwrite
    3. In theory – yes. This is why you lock the BIOS, and should lock your boot loader with password. In this case – the “attacker” cannot override your boot settings with another device, and cannot override boot options in Linux. The tpm2_nvread command, as I have discovered after an upgrade, is somehow signed and registered to the TPM2 (I didn’t check what mechanism it was, but it did not allow me to pull data after OS update), so alternate executables won’t work, I think.

  9. lamhoangtung Says:

    Thanks for the quick response @etzion.

    I actually tried to boot from a Live USB Ubuntu, run `tpm2_nvread 0x1500016` and was able to retrieve the key. Even though I locked my BIOS and GRUB menu with password, and disable boot from external device like USB, the setup still bug me with 2 question:
    1. According to this: https://github.com/fox-it/linux-luks-tpm-boot. I learned that Microsoft’s Bitlocker will take ownership of the TPM and it will not release the decryption keys to a changed O/S. So in case of a zero day vulnerability of a BIOS was used to boot into another OS, the approach that BitLocker use will still works. What should I try to take it from here and have something like that (I tried that repo and it does not work yet), just asking you to get some direction before trying again :3
    2. Since I don’t have a separate TPM chip. I used Intel Platform Trust Technology (PTT) (my CPU and Motherboard support it), which looks the same as a TPM 2.0 to the OS. So I’m not sure if a BIOS reset (via jumper) will clear the Intel PTT? Or if the attacker just took aways the whole pack of (CPU + Hard Drive) and put it into another machine, will the Intel PTT be clear ? Do you have any experience with Intel PTT ? Can you comment on this question ?

    Again, thanks for the amazing blog

  10. etzion Says:

    There are several methods to enforce harder. The first would be to use ‘grub-standalone’ with GPG signature (for the kernel and modules) internally. Since I did not invest the time in mapping how to automate this process for each time Ubuntu updates a kernel (and with it – initramfs), I have never written anything about it. But this is a very valid, hard-to-perform, and very-hard-to-override act.
    The idea is that you replace your whole grub_calls_kernel_and_initramfs_where_someone_can_replace_a_component with a single file (aka – grub standalone) with a private GPG key embedded, with the kernel and initramfs signed, so that the GRUB can (and will) load them; and the GRUB standalone itself is signed using a self-signed certificate the TPM is familiar with, and only you can re-sign it. So the trust flow goes like this:
    BIOS TPM has custom CA and certificate, which you control; grub standalone is signed using this CA, and only files signed by this CA are allowed to boot; grub standalone has embedded GPG key (as well as all the required modules built-in, with no ability to load external grub drivers), which is used to verify the kernel and the initramfs signatures. You add to this mess password protecting your grub, and I hope for your sake you never forget the passwords involved.

    About BitLocker – there are several methods of using TPM2 chip. The simple one allows keeping there keys, like in this article. The other is about placing SSL CA-approved key in it, and allowing the TPM to verify a signature of a request in order to provide the key, or something around this flow. This, too, was way too complex, compared to the level of protection I was aiming at, so I didn’t go there.

    If it works like TPM, it is TPM, meaning that if you reset your BIOS, the TPM keys are gone. You are most invited to check it (just have a backup of your key somewhere, or have another key placed into LUKS, and know this one)

    Good luck. Keep me posted. You’ve made me curious 🙂

  11. lamhoangtung Says:

    Thanks for the quick response @etzion.

    I will try reset BIOS or replacing the CPU first to see the Intel PTT works for my self :P. Will get u updated.

    Also, I will looks around and read more about “grub-standalone’ with GPG signature”.

  12. sf Says:

    Thanks so much for publishing this.
    However I’ve noticed you are currently not linking to the tpm2-getkey bash code but instead you are linking twice to the tpm2-decryptkey code.
    Hopefully you will be able to correct this soon.


  13. etzion Says:

    That is true. It seems that an add-on I am using to make my scripts more visible is failing the cache tests, and causing the whole cache of the Internet to show the same script twice. Weird. I have modified its settings enough to override it, although it is less pretty now.
    Thanks for letting me know!

  14. sf Says:

    Thanks for response @etzion.
    Just got it all working 🙂

    One question re updates:
    You say that the askpass addition makes this setup update-proof: Could you explain what you mean by this please?

    Tks SF

  15. etzion Says:

    I’ve meant that if and when you update something and break the scripts (let’s say that TPM commands were broken, or that your TPM was somehow erased) – you will still be able to manually enter the passphrase to unlock your disk, even if the TPM does not serve it anymore. It will allow you to survive faulty updates, without locking yourself out. And that is verified, because I have tested such a scenario as well (where TPM was not working well) and it did fail-over to manually asking for password. In the original note for Ubuntu 18.04, at least in the initial post release, the script could not handle TPM failures, and would kick you to a boot loop, where there is no method of entering the passphrase. A comment there (which I greatly appreciate) has pointed the way towards a failover-capable solution.

    Hope it explains.

  16. SC Says:

    I’ve followed these instructions, but when I boot and get to the unlock stage, I get ” /usr/local/sbin/tpm2-getkey: line 11: tpm2_nvread: not found \n Nothing to read on input.” The manual password entry works fine, so I can get back in, but I don’t know what the issue is with my getkey

  17. etzion Says:

    It seems as tpm2_nvread command is missing in your initramfs file. What do you get (in a booted OS) when you type ‘which tpm2_nvread’?

  18. SC Says:

    Booted and logged in:
    [email protected]_server:~$ which tpm2_nvread

    Thanks for the help with this

  19. etzion Says:

    Could you verify /usr/local/sbin/tpm2-getkey ? This script should identify and collect your tpm2_nvread, per its 15th line. You might want to replace this line with “copy_exec /usr/bin/tpm2_nvread” instead and recreate initramfs (subsection “Backup the original initrd and create a new one”)

  20. etzion Says:

    Check the created file “/etc/initramfs-tools/hooks/tpm2-decryptkey”
    It should have, at its 14th line, something like:
    copy_exec `which tpm2_nvread`
    If it doesn’t – fix it, or replace it with:
    copy_exec /usr/bin/tpm2_nvread
    and recreate initramfs, per the subsection “Backup the original initrd and create a new one”

  21. SC Says:

    My “/etc/initramfs-tools/hooks/tpm2-decryptkey” has ‘copy_exec /usr/bin/tpm2_nvread’ on the 14th line, which I assume was changed automatically from the “copy_exec `which tpm2_nvread`” I put in the file. I recreated initramfs anyway but there was no difference, the output at boot still says:
    /usr/local/sbin/tpm2-getkey: line 11: tpm2_nvread: not found
    Nothing to read on input.

    /usr/local/sbin/tpm2-getkey does have ‘tpm2_nvread 0x1500016’ on line 11, the last line.

  22. SC Says:

    I don’t know what the issue was, but it’s now resolved. If I can isolate the cause, I’ll let you know! Thanks for the terrific write up and your support.

  23. etzion Says:

    I am glad it is resolved and working.

  24. Jorge Says:

    This is amazing! I always knew there had to be a way of doing this. Thank you so much!

  25. Paolo C. Says:

    A couple of thoughts I wanted to share with you.
    1) Don’t you think that from some points of view this procedure weakens a system? I mean, BEFORE the ‘tweak’ to go past the encryption an attacker needed the key, now if he stole my PC (with the hard disk inside) he can decrypt and proceed with the boot.
    2) The problem that a user with sudo privs can ‘reverse engineer’ the pwd is not secondary. It makes the procedure unfeasible for the use case in which you want to give a third part (customer) full control on the device but avoid the disk to be booted elsewehere (recover password – nvwrite in another TPM – boot will work)
    3) Is there a way to obtain a NON TAMPERABLE, NON CHANGEABLE unique ID from the TPM, that you know?

    Thanks for the great work, keep on with it!!


  26. etzion Says:

    The best security would be achieved with a turned off, disconnected, and, preferably, empty and uninstalled computer. In real life, we need to find some balance between the usability and security, to get something done.
    Keeping your secrets in the TPM saves typing the decryption password every time. It will not allow an attacker who doesn’t know your user’s password access to the disk still. It will not allow an attacker to obtain the password from the TPM without that specific OS running, to which the attacked does not have credentials. Of course – security is measured by the weakest link in the chain, so if your password is very simple and allows easy hacking, you are likely to get your data stolen, or guessed, but it doesn’t matter – if the attacker has access to your account, what is the use of cracking your TPM? The attacker already had access to your files, so all this security is for nothing.
    Keep your passwords safe enough, your OS updated, your BIOS password protected, disk encrypted with TPM enabled, and GRUB password (and better – GPG signed) to prevent tempering, and the efforts of getting into your computer would be so high (although it’s never really impossible, if enough resources are put into it. Don’t assume you will be able to resist the NSA, or some other organisation this big for too long), so a random thief would find it easier resetting and cleaning the laptop than attempting to get your files – which is usually the case anyhow.
    It just has to be hard enough, and either with or without TPM (given the other security measures pointed both here and in the post itself) – the difference is minor. It’s just you, then, who saves typing a long passphrase every time you reboot your computer.

  27. JRDavisUF Says:

    Minor note, the text references 64 bits, but your example is coded using 64 bytes (tpm2_nvdefine -s 64 … and head -c 64 …)

    Perhaps to simplify the comparison between the nvread and file, ie who wants to compare 64 characters :), you could reference a command like: tpm2_nvread 0x1500016 | diff – root.key || echo “Key mismatch: TPM2 Read vs. File”


  28. etzion Says:

    You are correct. I will update the post.

  29. JRDavisUF Says:

    Thanks, you got one, but it looks like “bit” still exists here: “Create a random 64 bit key file:”

    It took me a bit to figure out how to automatically unencrypt a non-boot partition using the above process, so I figured I mention how I did it and ideas on how the guide above might be modified to make things easier for those attempting to do this in the future. First, by default, the initramfs hook “processes the root device, any resume devices and any devices with the initramfs option set.” As such, if you have some other drive that you’d also like to unencrypt at boot using the above approach you would need to add the “initramfs” flag at the end of any appropriate line in /etc/crypttab. Although redundant, I think this might be more clearly expressed in the docs above by having the user add “,keyscript=/usr/local/sbin/tpm2-getkey,initramfs” instead of just the keyscript part.

    Second, the example tpm2-getkey script won’t work for multiple drives because the name of the tmp file would be the same for each. The first time its called works, but not the second. Additionally, outputting () in the askpass line doesn’t really provide any useful info. Luckily, when running the keyscript command has access to several environment variables to make distinguishing between multiple drives clear for both operation and logging. As such, I modified the script to look like:


    # CRYPTTAB_NAME = sda3_crypt
    # CRYPTTAB_SOURCE = /dev/sda3


    if [ -f “${TMP_FILE}” ]; then
    # tmp file exists, meaning we tried the TPM this boot, but it didn’t work for the drive and this must be the second
    # or later pass for the drive. Either the TPM is failed/missing, or has the wrong key stored in it.
    /lib/cryptsetup/askpass “Automatic disk unlock via TPM failed for ($CRYPTTAB_SOURCE) Enter passphrase: ”
    # No tmp, so it is the first time trying the script. Create a tmp file and try the TPM
    touch ${TMP_FILE}

    tpm2_nvread 0x1500016

    Hope this saves others some time 🙂

  30. etzion Says:

    Thank you. I have corrected the additional location. Missed this one…

    This is not a common case to have multiple encrypted volumes which should be available at boot time, so I have not tested it, and to be frank – did not even think of that. So your contribution is much appreciated – thank you!

Leave a Reply