Cracking LUKS/dm-crypt passphrases
diverto.github.io
diverto.github.io
I had a NAS with a 22 characters passphrase that I had up and running for years and eventually forgot the password to. When I set it up I practiced the password enough times that I was sure I would never forget it so I never stored it anywhere. After years of never rebooting the NAS parts of the passphrase eventually got blurry and when I was about to move I realized I couldn't remember it anymore. I didn't really have anything of high value stored on it, but it kind of became a pet project to try to "crack" into it again. Together with Hashcat and the extracted header I eventually managed to brute force it after a couple of weeks :)
The worst part about the process was that it was hard to create rules for Hashcat to generate all different possibilities for the passphrase with all the information I knew about it baked in.
Since the article doesn't document any (new) luks weaknesses, none of the comments will be about luks being insecure.
Do you have some links to reference material on how to achieve that?
to avoid forgetting it use a string of words that make sense to your brain[1] but are unlikely to be encountered in the wild (in any texts).
Example passphrase: "My hamster kicks soapy homework with smurf locks like a tandem at 45 o clock!"
Then use this to generate a hash which can never be remembered in itself, and is unlikely to be brute-forced:
$ echo -n "My hamster kicks soapy homework with smurf locks like a tandem at 45 o clock!" | sha512sum
7364796a1ad957d7c524165aa2fec2501eaa59e6bd8380bad3252504cdb8592018e30ae2fff1b2c2295e6da7a7f47f52ef1c0e3010c054598d76fe0c6d64bac6 -
this way there is no need to remember the hash itself as long as you know how to recreate the hash (+ have the tooling present like sha512sum).In case you want to change the hash without having to remember a new passphrase just twiddle with the input string (by changing one character only) to get a totally new hash.
If you're on a multi-tenant machine this is probably dangerous since running `ps` might show other users on the system the input string when you run the command. Not an issue with single user systems. In case you want to avoid the command being recorded in your shell history file you can prefix the whole command with a blank (space).
Benefit of this is you get a pretty long hash that is impossible to brute-force and extremely hard to remember, which makes it really useful as a master-password.
An example attack would be an attacker compromises the password database of a site you use, and that site doesn't hash passwords. Next the attacker cracks that hash, which requires your password to be somewhat weak, but is aided by you not using a slow hash. Next the attacker uses that cracked master password variation to crack your LUKS setup. While LUKS uses a slow memory-hard hash, the attacker doesn't need to do many attempts, because the password is a small variation of the password the attacker already knows.
>in that case it matters what the website below in the stack uses.
I'm not sure exactly what this means. Are you saying you should put your security in the hands of website operators? I don't think you can rely on them. According to HIBP, I've been compromised by 25 breached sites and 28 pastes. I try to design my password scheme such that no matter how bad a site's security is, it has no impact on the security of anything besides that site. DyslexicAtheist's scheme doesn't have that property.
You already do regardless of which password you choose.
That said, I don't really see the point since it's no more secure than just using the long passphrase directly.
a 5 word passphrase isn't automatically more secure than a 5 char password if the words are predictable. interesing paper goes into this[1]. brains are generally bad in coming up with good passphrases (not enough entropy :)).
while my example is certainly very hard to predict I want to rule out an attacker predicting what makes the (nonsensical) passphrase.
https://eprint.iacr.org/2016/246.pdf
Edit: there is also a video to the above paper: https://www.youtube.com/watch?v=6-vrumB0UUw
So to get anything out of doing this is basically just assuming that your attacker won't know (or guess) that you're doing this. Maybe it doesn't hurt, but I wouldn't trust it with a low entropy passphrase. I suppose one use for it would be getting more entropy on sites with low password length requirements, like 10-15 characters max.
Another possible problem is if your computer gets stolen and the `echo xxx | sha512sum` command is in your .bash_history file. To me this seems to add a lot of additional risk.
On the other hand, if you are in a position to be using full-width keys, just use /dev/urandom to generate them instead of a password.
And sometimes you have a really good long password that decays in your memory until you can't get it right. After few hundred tries you must either give up or start cracking it systematically using parts that you remember.
As the sibling commenter and article point out, LUKS2 defaults to argon2i with 2 seconds of iteration time and 1GB of memory, 4 threads.
https://gitlab.com/cryptsetup/cryptsetup/blob/master/configu...
CS_NUM_WITH([luks1-iter-time], [PBKDF2 iteration time for LUKS1 (in ms)], [2000])
See also https://gitlab.com/cryptsetup/cryptsetup/blob/master/lib/uti... . const struct crypt_pbkdf_type default_pbkdf2 = {
.type = CRYPT_KDF_PBKDF2,
.hash = DEFAULT_LUKS1_HASH,
.time_ms = DEFAULT_LUKS1_ITER_TIME
};But for any of them, they can copy the relevant section to crack, and bruteforce massively in parallel.
So I use ~50 character passphrases for LUKS. None are written or stored. All from my memory.
Still, with enough fast processors working in parallel, that could probably be cracked within a few years.
But then, given my age, there's a fair chance that I'd be dead before they managed it.
Let's do some napkin math. I'm going to make a blind assumption that you are a native English speaker, which gives us entropy estimate of ~1 bit per character.[0] Let's be generous and assume your passphrase has 51 bits of entropy, which makes the following numbers nice and round.
To exhaustively search through half the passphrase space, the cracking rig will need to try 2^{50} =~ 10^{15} times. [50 * ln(2) =~ 50 * 0.301]
The default master password hashing scheme in LUKS is PBKDF2, and for modern setups, argon2. The article throws around a few hashing speed ballparks, but depending on the setup we're talking about on the order of 1000 hashing attempts per second, per core. (Yes yes, the OP has figures with the argon2 numbers at about half that - I'm being very conservative here.)
So, for a single LUKS passphrase crack we're talking, on average, of about 10^{12} core-seconds. A core-year is about 3 * 10^{7} seconds. So, with a single core the brute-force would take, on average, about 10^{5} years.
As such... in order to break one of your passphrases, an attacker would need to dedicate 10k core-years of CPU time. That's a lot of hardware and cooling, but it's certainly not infeasible. You would need to be pretty attractive/dangerous/high-value target for anyone to spend that kind of money, though.
Then the final step, threat modeling. For a normal techie, a passphrase like yours should be safe enough. For someone with access to material such as top hedge fund secrets, or into dangerous and politically juicy activities, attacking their passphrase is well within reach of a determined and well funded organisation.
0: https://people.seas.harvard.edu/~jones/cscie129/papers/stanf...
Me, I'm just some anonymous coward who putters with privacy/anonymity stuff, and writes about it online.
The funny part is that they'd arguably need to spend as much to even access those LUKS volumes. That'd be quite the joke on them.
Also, I'm not sure if the theoretical entropy levels are ever reached by real password crackers. I think they tend to use more basic rules. In that case I think zxcvbn might provide a better estimate (multiply guesses_log10 by 3.3 to get bits). But if your password contains a phrase that has ever been written publicly, the entropy massively decreases.
Now, admittedly for me a passphrase is something that could be identified and processed by NLP-like construction. (Hence it could be also produced by one.) A sequence of random words requires, at least in my case, to come up with a special mnemonic.
As a sibling post points out, if the phrase is generated by diceware (iow. sequence of words chosen at random from a large dictionary), then the entropy would be way, way higher - so high in fact that bruteforcing might be eclipsed by heat death of the universe.
Assume you had a word list of the 10000 most common English words, and picked six of them at random. That's probably less than the 50 characters you're assuming.
There are 10000^6 combinations, so 10000^6/2 guesses required. Assume you can hash 1000/s per core (IMO if your attacker can get that your hash setting are too weak)...
So it's going to take 10000^6/2/1000/(3*10^7) core years to crack. If you can devote 1200 CPU cores to this project, you have a 50/50 shot at cracking the password by the time the universe is twice as old as it is now.
And that's just by taking the most obvious of steps to generate a better password, which (again) is probably still less than 50 characters.
I assumed, perhaps naively, that due to use of the term passphrase we were discussing a sequence of words that might be identified, and thus also likely generated by, an NLP-like system. After all, the ~1b/chr estimate only holds true with English language texts.
But actually, my LUKS passphrases are sequences of letters and numbers. They're based on favorite quotations. With the standard leet letter->number replacements, and no punctuation or spaces. So they're easy to reconstruct (from my books) if I forget them.
can someone ELI5 how they do 882 hashes per second if PBKDF2 is set up to take 2 seconds, for example? What's so broken about PBKDF2 that they get a > 1000x speedup?
The annoying thing is LUKS1 only supports PBKDF2, but LUKS2 comes with a JSON parser, and no full support everywhere yet
N.B. sorry for typos, have a cat in the way
The other thing that slows them down is memory access. Caches are small because everything adds up quickly once you multiply it by a few thousand. They are optimized for access patterns typical in graphics, which is mostly sequential or every-x-bytes. The main memory might be GDDR5 or GDDR6, but even the 600GB/s memory bandwidth of the RTX 2080TI is quickly used up once you have 8000 threads requesting random bytes from memory.
Apart from branching and memory I don't think GPUs have many weaknesses. They can save a lot of transistors because they don't care about single-core performance. For example instead of doing sophisticated instruction reordering to hide memory latency they just switch to a different set of threads whenever they would otherwise wait for memory. There are some tasks that Intel CPUs have transistors dedicated to like AES or 64bit integers and they do loose some speed on those, but at the same time these things are easy to do in silicon so your CPU loses to ASICs. And even a GPU eventually has enough cores that the software implementation run 4000 times in parallel will beat the CPU by a wide margin again.
I recently wanted to do exactly that in JavaScript. Browser crypto only does PBKDF2... quite disappointing. One still has to use third party libraries for all practical purposes, there might as well not be a crypto API at all except for providing a CSPRNG.
* The "2 seconds" is used measure a specific number of algorithm iterations running a specific software implementation on the host CPU when the volume is initialized. This count is static after initialization.
* If an attacker has a faster device, or a lot of cores, or both (GPU), the attacker can do more iterations per second. Thus, it takes them fewer seconds (potentially fractions of a second) per guess.
> What's so broken about PBKDF2 that they get a > 1000x speedup?
Nothing in particular; it lacks some of the memory hardness that newer KDFs have. The attacker gets 1000x speedup by throwing something like 1000x the compute at the problem. (This is a little cheaper than it might seem because the problem is tractable on GPU.)
Note that LUKS by default sets the number of PBKDF2 iterations to take 1 second, not 2.
You can also use a private gpg key and an gpg-encrypted keyfile. Yubikey can store gpg keys (with attestation if you want), and you can enable both yubikey access and gpg in initramfs. That's good for servers if you pair it with initramfs sshd.
TPM is kind of broken, as I understand it, so I didn't even bother looking into it. There's really no reason I can't carry my keys on my physical keychain, so I don't see a need for TPM. I can also put a USB stick on my keychain and use that to boot.
That way even if an attacker has physical access to the hardware, it would be require some really advanced firmware/microcode hackery to compromise the machine.
TPM dies if your motherboard dies, so you'd need a backup key anyway.
There's also no way for you to independently audit the TPM device, so you don't know how secure it really is. Personally, I don't trust Intel to keep the TPM secure, as they've shown they can't (see the above link).
The keys are in the chip if you use them for FDE, so you're expanding your trust that someone with access to the TPM can never dump the keys. This could be a problem if your machine is stolen.
By going the yubikey route, you can move the trust to a device that's physically on your person. That way, if the machine is stolen, there's absolutely no way to recover the keys, and there never will be even if more intel vulnerabilities are found.
You could use a yubikey for the FDE keys, and only use TPM for trusting the boot device. But if you're already carrying a yubikey to decrypt your device, you might as well boot off USB too.
The real problem, like always, is key management. And knowing what is “overkill” for a given scenario, i.e. where reasonability ends. 8 MB is really something that should have some additional reasons than just protection from brute forcing the key.
LUKS2 uses argon2.
See, e.g., Cryptographic Right Answers[1]:
> Password handling
> Percival, 2009: scrypt or PBKDF2.
> Ptacek, 2015: In order of preference, use scrypt, bcrypt, and then if nothing else is available PBKDF2.
> Latacora, 2018: In order of preference, use scrypt, argon2, bcrypt, and then if nothing else is available PBKDF2.
[1]: https://latacora.micro.blog/2018/04/03/cryptographic-right-a...