mjg59
Here's an article from a French anarchist describing how his (encrypted) laptop was seized after he was arrested, and material from the encrypted partition has since been entered as evidence against him. His encryption password was supposedly greater than 20 characters and included a mixture of cases, numbers, and punctuation, so in the absence of any sort of opsec failures this implies that even relatively complex passwords can now be brute forced, and we should be transitioning to even more secure passphrases.
Or does it? Let's go into what LUKS is doing in the first place. The actual data is typically encrypted with AES, an extremely popular and well-tested encryption algorithm. AES has no known major weaknesses and is not considered to be practically brute-forceable - at least, assuming you have a random key. Unfortunately it's not really practical to ask a user to type in 128 bits of binary every time they want to unlock their drive, so another approach has to be taken.
This is handled using something called a "key derivation function", or KDF. A KDF is a function that takes some input (in this case the user's password) and generates a key. As an extremely simple example, think of MD5 - it takes an input and generates a 128-bit output, so we could simply MD5 the user's password and use the output as an AES key. While this could technically be considered a KDF, it would be an extremely bad one! MD5s can be calculated extremely quickly, so someone attempting to brute-force a disk encryption key could simply generate the MD5 of every plausible password (probably on a lot of machines in parallel, likely using GPUs) and test each of them to see whether it decrypts the drive.
(things are actually slightly more complicated than this - your password is used to generate a key that is then used to encrypt and decrypt the actual encryption key. This is necessary in order to allow you to change your password without having to re-encrypt the entire drive - instead you simply re-encrypt the encryption key with the new password-derived key. This also allows you to have multiple passwords or unlock mechanisms per drive)
Good KDFs reduce this risk by being what's technically referred to as "expensive". Rather than performing one simple calculation to turn a password into a key, they perform a lot of calculations. The number of calculations performed is generally configurable, in order to let you trade off between the amount of security (the number of calculations you'll force an attacker to perform when attempting to generate a key from a potential password) and performance (the amount of time you're willing to wait for your laptop to generate the key after you type in your password so it can actually boot). But, obviously, this tradeoff changes over time - defaults that made sense 10 years ago are not necessarily good defaults now. If you set up your encrypted partition some time ago, the number of calculations required may no longer be considered up to scratch.
And, well, some of these assumptions are kind of bad in the first place! Just making things computationally expensive doesn't help a lot if your adversary has the ability to test a large number of passwords in parallel. GPUs are extremely good at performing the sort of calculations that KDFs generally use, so an attacker can "just" get a whole pile of GPUs and throw them at the problem. KDFs that are computationally expensive don't do a great deal to protect against this. However, there's another axis of expense that can be considered - memory. If the KDF algorithm requires a significant amount of RAM, the degree to which it can be performed in parallel on a GPU is massively reduced. A Geforce 4090 may have 16,384 execution units, but if each password attempt requires 1GB of RAM and the card only has 24GB on board, the attacker is restricted to running 24 attempts in parallel.
So, in these days of attackers with access to a pile of GPUs, a purely computationally expensive KDF is just not a good choice. And, unfortunately, the subject of this story was almost certainly using one of those. Ubuntu 18.04 used the LUKS1 header format, and the only KDF supported in this format is PBKDF2. This is not a memory expensive KDF, and so is vulnerable to GPU-based attacks. But even so, systems using the LUKS2 header format used to default to argon2i,again not a memory expensive KDFwhich is memory strong, but not designed to be resistant to GPU attack (thanks to the comments pointing out my misunderstanding here). New versions default to argon2id, which is. You want to be using argon2id.
What makes this worse is that distributions generally don't update this in any way. If you installed your system and it gave you pbkdf2 as your KDF, you're probably still using pbkdf2 even if you've upgraded to a system that would use argon2id on a fresh install. Thankfully, this can all be fixed-up in place. But note that if anything goes wrong here you could lose access to all your encrypted data, so before doing anything make sure it's all backed up (and figure out how to keep said backup secure so you don't just have your data seized that way).
First, make sure you're running as up-to-date a version of your distribution as possible. Having tools that support the LUKS2 format doesn't mean that your distribution has all of that integrated, and old distribution versions may allow you to update your LUKS setup without actually supporting booting from it. Also, if you're using an encrypted /boot, stop now - very recent versions of grub2 support LUKS2, but they don't support argon2id, and this will render your system unbootable.
Next, figure out which device under /dev corresponds to your encrypted partition. Run
lsblk
and look for entries that have a type of "crypt". The device above that in the tree is the actual encrypted device. Record that name, and run
sudo cryptsetup luksHeaderBackup /dev/whatever --header-backup-file /tmp/luksheader
and copy that to a USB stick or something. If something goes wrong here you'll be able to boot a live image and run
sudo cryptsetup luksHeaderRestore /dev/whatever --header-backup-file luksheader
to restore it.
(Edit to add: Once everything is working, delete this backup! It contains the old weak key, and someone with it can potentially use that to brute force your disk encryption key using the old KDF even if you've updated the on-disk KDF.)
Next, run
sudo cryptsetup luksDump /dev/whatever
and look for the Version: line. If it's version 1, you need to update the header to LUKS2. Run
sudo cryptsetup convert /dev/whatever --type luks2
and follow the prompts. Make sure your system still boots, and if not go back and restore the backup of your header. Assuming everything is ok at this point, run
sudo cryptsetup luksDump /dev/whatever
again and look for the PBKDF: line in each keyslot (pay attention only to the keyslots, ignore any references to pbkdf2 that come after the Digests: line). If the PBKDF is either "pbkdf2" or "argon2i" you should convert to argon2id. Run the following:
sudo cryptsetup luksConvertKey /dev/whatever --pbkdf argon2id
and follow the prompts. If you have multiple passwords associated with your drive you'll have multiple keyslots, and you'll need to repeat this for each password.
Distributions! You should really be handling this sort of thing on upgrade. People who installed their systems with your encryption defaults several years ago are now much less secure than people who perform a fresh install today. Please please please do something about this.
Or does it? Let's go into what LUKS is doing in the first place. The actual data is typically encrypted with AES, an extremely popular and well-tested encryption algorithm. AES has no known major weaknesses and is not considered to be practically brute-forceable - at least, assuming you have a random key. Unfortunately it's not really practical to ask a user to type in 128 bits of binary every time they want to unlock their drive, so another approach has to be taken.
This is handled using something called a "key derivation function", or KDF. A KDF is a function that takes some input (in this case the user's password) and generates a key. As an extremely simple example, think of MD5 - it takes an input and generates a 128-bit output, so we could simply MD5 the user's password and use the output as an AES key. While this could technically be considered a KDF, it would be an extremely bad one! MD5s can be calculated extremely quickly, so someone attempting to brute-force a disk encryption key could simply generate the MD5 of every plausible password (probably on a lot of machines in parallel, likely using GPUs) and test each of them to see whether it decrypts the drive.
(things are actually slightly more complicated than this - your password is used to generate a key that is then used to encrypt and decrypt the actual encryption key. This is necessary in order to allow you to change your password without having to re-encrypt the entire drive - instead you simply re-encrypt the encryption key with the new password-derived key. This also allows you to have multiple passwords or unlock mechanisms per drive)
Good KDFs reduce this risk by being what's technically referred to as "expensive". Rather than performing one simple calculation to turn a password into a key, they perform a lot of calculations. The number of calculations performed is generally configurable, in order to let you trade off between the amount of security (the number of calculations you'll force an attacker to perform when attempting to generate a key from a potential password) and performance (the amount of time you're willing to wait for your laptop to generate the key after you type in your password so it can actually boot). But, obviously, this tradeoff changes over time - defaults that made sense 10 years ago are not necessarily good defaults now. If you set up your encrypted partition some time ago, the number of calculations required may no longer be considered up to scratch.
And, well, some of these assumptions are kind of bad in the first place! Just making things computationally expensive doesn't help a lot if your adversary has the ability to test a large number of passwords in parallel. GPUs are extremely good at performing the sort of calculations that KDFs generally use, so an attacker can "just" get a whole pile of GPUs and throw them at the problem. KDFs that are computationally expensive don't do a great deal to protect against this. However, there's another axis of expense that can be considered - memory. If the KDF algorithm requires a significant amount of RAM, the degree to which it can be performed in parallel on a GPU is massively reduced. A Geforce 4090 may have 16,384 execution units, but if each password attempt requires 1GB of RAM and the card only has 24GB on board, the attacker is restricted to running 24 attempts in parallel.
So, in these days of attackers with access to a pile of GPUs, a purely computationally expensive KDF is just not a good choice. And, unfortunately, the subject of this story was almost certainly using one of those. Ubuntu 18.04 used the LUKS1 header format, and the only KDF supported in this format is PBKDF2. This is not a memory expensive KDF, and so is vulnerable to GPU-based attacks. But even so, systems using the LUKS2 header format used to default to argon2i,
What makes this worse is that distributions generally don't update this in any way. If you installed your system and it gave you pbkdf2 as your KDF, you're probably still using pbkdf2 even if you've upgraded to a system that would use argon2id on a fresh install. Thankfully, this can all be fixed-up in place. But note that if anything goes wrong here you could lose access to all your encrypted data, so before doing anything make sure it's all backed up (and figure out how to keep said backup secure so you don't just have your data seized that way).
First, make sure you're running as up-to-date a version of your distribution as possible. Having tools that support the LUKS2 format doesn't mean that your distribution has all of that integrated, and old distribution versions may allow you to update your LUKS setup without actually supporting booting from it. Also, if you're using an encrypted /boot, stop now - very recent versions of grub2 support LUKS2, but they don't support argon2id, and this will render your system unbootable.
Next, figure out which device under /dev corresponds to your encrypted partition. Run
lsblk
and look for entries that have a type of "crypt". The device above that in the tree is the actual encrypted device. Record that name, and run
sudo cryptsetup luksHeaderBackup /dev/whatever --header-backup-file /tmp/luksheader
and copy that to a USB stick or something. If something goes wrong here you'll be able to boot a live image and run
sudo cryptsetup luksHeaderRestore /dev/whatever --header-backup-file luksheader
to restore it.
(Edit to add: Once everything is working, delete this backup! It contains the old weak key, and someone with it can potentially use that to brute force your disk encryption key using the old KDF even if you've updated the on-disk KDF.)
Next, run
sudo cryptsetup luksDump /dev/whatever
and look for the Version: line. If it's version 1, you need to update the header to LUKS2. Run
sudo cryptsetup convert /dev/whatever --type luks2
and follow the prompts. Make sure your system still boots, and if not go back and restore the backup of your header. Assuming everything is ok at this point, run
sudo cryptsetup luksDump /dev/whatever
again and look for the PBKDF: line in each keyslot (pay attention only to the keyslots, ignore any references to pbkdf2 that come after the Digests: line). If the PBKDF is either "pbkdf2" or "argon2i" you should convert to argon2id. Run the following:
sudo cryptsetup luksConvertKey /dev/whatever --pbkdf argon2id
and follow the prompts. If you have multiple passwords associated with your drive you'll have multiple keyslots, and you'll need to repeat this for each password.
Distributions! You should really be handling this sort of thing on upgrade. People who installed their systems with your encryption defaults several years ago are now much less secure than people who perform a fresh install today. Please please please do something about this.
Thanks for the heads up!
Date: 2023-04-18 01:57 am (UTC)systemd-cryptenroll
Date: 2023-04-18 04:00 am (UTC)I use
systemd-cryptenroll
for TPM–based automatic unlock. I’m sure doing so is a bad idea for many reasons, but regardless, I noticed the LUKS keyslot thatsystemd-cryptenroll
creates is hardcoded topbkdf2
.Indeed, looking at the source, it appears this decision was made because the author “found the Wikipedia entry relevant”:
Re: systemd-cryptenroll
Date: 2023-04-18 04:42 am (UTC)Re: systemd-cryptenroll
From: (Anonymous) - Date: 2023-04-18 07:29 am (UTC) - ExpandRe: systemd-cryptenroll
From: mjg59 - Date: 2023-04-18 07:40 am (UTC) - ExpandRe: systemd-cryptenroll
From: (Anonymous) - Date: 2023-04-18 07:55 am (UTC) - ExpandRe: systemd-cryptenroll
From: mjg59 - Date: 2023-04-18 08:12 am (UTC) - ExpandRe: systemd-cryptenroll
From: romanticboy.livejournal.com - Date: 2023-11-25 12:44 am (UTC) - ExpandRe: systemd-cryptenroll
From: (Anonymous) - Date: 2023-04-18 07:48 pm (UTC) - ExpandArgon2i is memory hard
Date: 2023-04-18 04:00 am (UTC)Argon2 is parameterized by CPU cost, memory cost, and parallelization factor. You can read more at https://github.com/P-H-C/phc-winner-argon2, but Argon2 is memory hard, which includes Argon2i, Argon2d, and the hybrid Argon2id.
Re: Argon2i is memory hard
Date: 2023-04-18 03:19 pm (UTC)Yeah, I saw this submitted on Lobsters and /r/crypto, and went a bit angry and impolite there.
The only way Argon2i is not memory hard would be a new attack I’m not aware of. The author needs to cite their source here. Because whether they’re right or wrong this is kind of important.
Re: Argon2i is memory hard
From: mjg59 - Date: 2023-04-18 06:36 pm (UTC) - Expandno subject
Date: 2023-04-18 04:38 am (UTC)So that's at least 64^20 = 2^120 variants. I call bullshit on brute-forcing. There was some kind of opsec failure.
no subject
Date: 2023-04-18 04:39 am (UTC)(no subject)
From: (Anonymous) - Date: 2023-04-18 06:57 am (UTC) - Expand(no subject)
From: (Anonymous) - Date: 2023-04-18 10:23 am (UTC) - Expand(no subject)
From: (Anonymous) - Date: 2023-04-18 05:19 pm (UTC) - Expand(no subject)
From: (Anonymous) - Date: 2023-04-19 12:20 am (UTC) - Expandthe problem is the password
From: (Anonymous) - Date: 2023-05-06 12:04 pm (UTC) - ExpandPKBDF2
Date: 2023-04-18 06:52 am (UTC)Unfortunately, PBKDF2 is still the only KDF approved by NIST. While this doesn't affect home users, companies that are required to comply with US government regulations are stuck with PBKDF2 for now. Yet another case where NIST's regulations eventually yield questionable security...
no subject
Date: 2023-04-18 08:09 am (UTC)That said, as a PSA it is not very good. Consider adding a TL;DR or summary. Few people will actually reach the bottom as it's quite a bit of introduction.
"Delete this backup"
Date: 2023-04-18 08:36 am (UTC)You mention to delete the luksHeader backup, but you don't mention it should be deleted using wipe(1).
HTH,
Colin
Re: "Delete this backup"
Date: 2023-04-18 09:35 am (UTC)Re: "Delete this backup"
From: (Anonymous) - Date: 2023-04-18 11:30 am (UTC) - ExpandRe: "Delete this backup"
From: (Anonymous) - Date: 2023-04-18 02:14 pm (UTC) - ExpandRe: "Delete this backup"
From: (Anonymous) - Date: 2023-04-18 05:58 pm (UTC) - ExpandRe: "Delete this backup"
From: (Anonymous) - Date: 2023-04-19 08:01 am (UTC) - ExpandRe: "Delete this backup"
From: (Anonymous) - Date: 2023-06-22 12:18 am (UTC) - ExpandChanging KDF of digest
Date: 2023-04-18 11:32 am (UTC)thanks for this helpful post.
I have successfully changed the KDF to argon2id for my keyslots, however, the digest is still using pbkdf2:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 149114
Salt: xxx
Digest: xxx
Is this a security issue? Is is possible to change this to argon2id as well?
Re: Changing KDF of digest
Date: 2023-04-18 05:50 pm (UTC)Re: Changing KDF of digest
From: (Anonymous) - Date: 2023-10-01 09:08 pm (UTC) - Expandno subject
Date: 2023-04-18 11:59 am (UTC)By the way SHA2 is not really slower than MD5 at all. It is even designed to be fast. The cracking of passwords is hard because of the exponential search space, not because of the algorithm speed. 128 bits are impossible to brute force, so even MD5 is safe in this regard. It is vulnerable to collision attacks, but that does not help with password cracking.
Because of this, KDF slowdown is snakeoil for many applications. The complexity of the password is more important than the slowdown of the KDF function. However, it makes a practical difference so your recommendations are still valid for disk and file encryption.
no subject
Date: 2023-04-18 05:51 pm (UTC)(no subject)
From: (Anonymous) - Date: 2024-03-25 07:02 am (UTC) - ExpandInitrd
Date: 2023-04-18 12:16 pm (UTC)It's pretty likely the group of people in this has been infiltrated at some point, or simply that the places have been for a few minutes at least Evil maid attacks are fairly quick to conduct when the target is simply the initrd.
Re: Initrd
Date: 2023-04-19 08:31 am (UTC)If Secure Boot is enabled, then grubx64.efi/shimx64.efi will fail if replaced/tampered with.
If the pass-string has sufficient degrees of freedom, a 'weak' key derivation function is not relevant.
Like others, I think OPSEC failure is more likely than technical failure. Good OPSEC is difficult.
Separate header
Date: 2023-04-18 12:34 pm (UTC)But anyway, it's always better to see if there's a way to break the encryption. So, thank you for this real good article, I guess, I will start converting the next days...
Re: Separate header
Date: 2023-04-18 01:15 pm (UTC)Interested in what you said.
How can I remove the header so the disk looks empty ?
Re: Separate header
From: (Anonymous) - Date: 2023-04-18 02:45 pm (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-18 08:03 pm (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-18 03:24 pm (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-19 01:33 pm (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-18 04:31 pm (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-19 01:52 am (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-19 07:29 am (UTC) - ExpandRe: Separate header
From: (Anonymous) - Date: 2023-04-19 08:07 am (UTC) - ExpandWorks for me
Date: 2023-04-18 12:59 pm (UTC)Is it possible that current openSUSE ships archaic bits of LUKS1 only?
Date: 2023-04-18 02:46 pm (UTC)Is it very much possible that funny de_DE folks at openSUSE ship archaic LUKS1 bits only? they never heard of argon and fancy year old and well aged means such as argon?
Very odd distro they have in the dark old world?
Guess they being left less protected. Who needs protection in dark middle ages of old Yurop anyways?
Re: Is it possible that current openSUSE ships archaic bits of LUKS1 only?
Date: 2023-04-18 04:36 pm (UTC)https://en.opensuse.org/SDB:LUKS2,_TPM2_and_FIDO2
Re: Is it possible that current openSUSE ships archaic bits of LUKS1 only?
From: (Anonymous) - Date: 2023-05-18 12:19 pm (UTC) - Expandno subject
Date: 2023-04-18 03:39 pm (UTC)GPU attacks against passwords
Date: 2023-04-18 03:41 pm (UTC)no subject
Date: 2023-04-18 04:29 pm (UTC)They will say in court they cracked it instead.
Keep your network secure, and be careful about apps. even trusted ones like signal, the authorities can push their own client that is a trojan. I had this happen to me.
Once they are on your network. all sorts of man in the middle attacks can be tailored to your operating system and software used.
no subject
Date: 2023-04-20 04:21 pm (UTC)Encryption is only as good as the user's opsec. If a password is being typed through the X server, it may be assumed that it has already been transmitted to an interested party of choice. For example: how many of us don't practice the boot partition passphrase a few tens of times in order to commit it to memory? There's even a --test-passphrase option in cryptsetup which enables just that. How many of us switch to the console, perhaps also kill the X server first, before doing that?
Thirdly, assuming keyloggers, the French security apparatus can just as easily present materials as supposedly haxxed from their target's computers when said materials were actually captured as they were typed. The custody chain is generally not very solid, nor its judicial requirements very strict, in "political" cases.
(no subject)
From: (Anonymous) - Date: 2023-04-22 12:53 am (UTC) - ExpandFIDO2 tokens?
Date: 2023-04-18 05:59 pm (UTC)If not, how to do so? I found no way looking at the manpage.
Re: FIDO2 tokens?
Date: 2023-04-18 06:30 pm (UTC)no subject
Date: 2023-04-18 08:11 pm (UTC)Where is the indication that this was an attack against the KDF? For all we know they could have found a bug in the LUKS implementation.
Or much more realistically this was just an evil maid attack, or somebody got his password via "non-technical" means like filming him typing it in a cafe.
Beware upstream GRUB does not support argon2i / argon2id
Date: 2023-04-18 08:45 pm (UTC)https://wiki.archlinux.org/title/GRUB#LUKS2
Re: Beware upstream GRUB does not support argon2i / argon2id
Date: 2023-04-18 08:57 pm (UTC)Re: Beware upstream GRUB does not support argon2i / argon2id
From: (Anonymous) - Date: 2023-04-18 10:07 pm (UTC) - ExpandRe: Beware upstream GRUB does not support argon2i / argon2id
From: (Anonymous) - Date: 2023-04-19 01:34 pm (UTC) - Expandno subject
Date: 2023-04-18 10:32 pm (UTC)no subject
Date: 2023-04-19 02:11 am (UTC)no subject
Date: 2023-04-19 07:39 am (UTC)(no subject)
From: (Anonymous) - Date: 2023-04-29 04:16 pm (UTC) - Expand(no subject)
From: (Anonymous) - Date: 2024-03-29 09:28 am (UTC) - Expandno subject
Date: 2023-04-19 08:13 am (UTC)Something in your analysis doesn't add up.
The user had ~128 bits of entropy. The alphabet they were using consists of 72 characters (26 lower case, 26 upper case, 10 numbers, 10 special characters). Their password length was at least 20. This comes out to
log(72**20, 2) = 123
bits of entropy. This much entropy is uncrackable. Unless there is a weakness in AES. The entropy is so high that no key derivation function is needed at all. Key derivation functions are useful to improve weak passwords, not strong ones.If the password was cracked then it was much weaker than the user claimed (maybe unknowingly). Maybe their password was not very random. Or it was not cracked at all and they got the password through other means.
(The recommendation to upgrade the key derivation function is still good.)
no subject
Date: 2023-04-19 08:21 am (UTC)(no subject)
From: mjg59 - Date: 2023-04-19 08:32 am (UTC) - Expand(no subject)
From: (Anonymous) - Date: 2023-04-19 01:00 pm (UTC) - Expandno subject
Date: 2023-04-19 02:15 pm (UTC)I don't think this is the correct takeaway from the situation. * What matters is not the length of the password ("20 characters") or included character groups ("letters, digits and symbols"), but its entropy. In particular, obfuscating a word with some digits or symbols does not really gain much. * A slow or memory-hard key derivation function is a band-aid, not a fix. Making hashing harder slows down the attacker linearly. Choosing a longer passphrase slows them down exponentially. * The victim used "Ubuntu 18". This is quite an old distribution and while still in extended support, many packages are not receiving proper security patches any more (IIRC, only "main" is fully supported, while the situation in "universe" is quite bad). It is quite likely that the machine was compromised at runtime.
So my takeaway would be: * Use a proper passphrase. The diceware method with 10 words is a good choice, giving you slightly more than 128 bits of entropy. The KDF does not matter than, it could even be a simple SHA-2. * Always use well-supported software, and do not skip updates. Do not install unneeded software, particularly on machines processing high-risk data. * In addition, make hardware-based attacks harder, particularly if you're a member of a vulnerable group. Check that nobody is watching you while entering the passphrase. Do not leave your computer unattended, especially when turned on or in suspend-to-RAM. Only buy computers in person, and do not use computers returned from police.
Unlikely to be brute forced
Date: 2023-04-20 02:35 am (UTC)A 21 character password with upper+lower case, numbers and popular punctuation has about 65^21 combinations.
Sure attackers can use many GPUs. Say you have 1 million devices that do 600 million SHA256 per second.
Say pbkdf2 with "only" 10,000 rounds of sha256.
65^21 x 10000 / (1 million x 600 million) seconds = 6.22206506 × 10^19 years. Sure in theory you'd probably might find it less than 50% of the way through but in practice you're going to use a different method.
Thus I doubt the problem was with pbkdf2 and I suspect this article is a distraction from the actual methods used/vulnerability exploited.
Re: Unlikely to be brute forced
Date: 2023-04-20 02:36 am (UTC)no subject
Date: 2023-04-20 06:17 am (UTC)no subject
Date: 2023-04-20 07:07 am (UTC)Also: Changing from PBKDF2 to Argon would prevent default GRUB from unlocking and booting an encrypted system.