-
-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Choose stronger encryption by default and/or re-use encryption parameters of LUKS container #1539
Comments
@UndeadDevel first things first, thanks for the good challenge on implementation. I just want to make sure we understand what is done today. Two cryptsetup modules exist under heads. Old modules/cryptsetup being 1.75 and newer modules/cryptsetup2 currently being 2.4.0 All boards configs are including modules/cryptsetup2 as of today. Now, the reencrypting functions we are talking about have limited arguments forced by Heads today: https://github.com/linuxboot/heads/blob/master/initrd/etc/luks-functions#L350 As pointed at line 350 :
This choices were made based on a tradeoff back then where assumptions made by cryptsetup were wrong and where ETA were otherwise exploding. Note that the passphrase stored under /tmp/ could be moved to /tmp/secrets to be wiped on recovery shell access even more securely by default codepath or on kexec path as well, but the assumption here again is that tmp is ramfs of initrd and recreated on reboot or overwritten on final os boot in all case, where the owner of the computer is supposed to be behind the computer and alone when doing re-ownership wizard. Also note the shred calls that follows usage in all case. The passphrase is not the key. The passphrase creates/unlocks the key. Slot 0 is forced here because the goal is to not add another key, but make sure that the installation key is overwritten in the best way possible. As you pointed out with 5.19 documentation of SSD drives from cryptsetup, there is not much more that can be done but overwrite it and leave physical forensic possible with soldering implied. Using SSD firmware secure erase was debated in other issues and under cryptsetup for years, and SSD doesn't offer better option then using encryption for the blocks. As also present on cryptsetup doc, entropy of passphrase is the important part here. So Heads again does the right thing here if a user decides to add a sealed TPM Disk Unlock Key, which passphrase is then a 128 random characters, sealed into TPM with firmware measurements, luks header measurements and runtime (loaded kernel modules, no recovery shell access) to be possible to be unsealed with a user selected passphrase which can then be of lower entropy, rate limited by tpm with a fallback of having final OS prompt for LUKS if heads doesn't know how to deal with that LUKS container. That TPM DUK generated passphrase is then unsealed and injected in kexec reconstructed final initrd which is passed to final Os and used to decrypt LUKS container without the user having to type high entropy passphrase in untrusted environment. Argon is reused if OS created LUKS container with it in version 2.4.0. Heads doesn't interfere with OS distribution choices as of today. Note, though, that this might need to be revisited (and cryptsetup2 module version bumped) if new platforms not having CPU AES extension are to be added under Heads. If today, OS decides to create LUKS container with Adiantum, then Heads will fail reencrypting it simply because neither Linux kernel nor cryptsetup 2.4.0 supports it. This impacts other architectures then x86/power and X86 i3 older generation CPU and was also discussed in other issues. Tldr: cryptsetup-reencryption under heads does not replace OS choices nor user selected settings as of today. Heads attempts to replace in place slot0 (directio, sector of 64 bytes) to mitigate OEM deployment bad practices and/or limit its liability to the moment user receives a computing device and decides to stop trusting the OEM/third party deployed keys from the moment of re-ownership. When a user installs an OS with LUKS settings that might not be supported by current version of cryptsetup deployed under Heads, cryptsetup-reencrypt calls will bail/fail. Maybe currently with not enough helpful information though. Todo: there is still one issue you tackled under another issue under nitrokey repo, that is, those luks functions should not create any file under /boot. This is still a bug because not all boards permit TPM sealed Disk Unlock Key. This will need refactoring and deserve a seperate issue. Note: new LUKS functions have been deployed recently to create LUKS container on USB thumb drive to store gpg key material backup, enabling+forcing authentication for recovery shell and USB boot. Those functions hardcode the best practices borrowed from qubesos LUKS container creation of their installer media.
As pointed by cryptsetup documentation, that LUKS container would not be really secure if the passphrase is left to the OEM factory defaults, which reuses GPG Admin PIN which by default is 12345678. Edit:many. |
@tlaurion Thanks for the detailed reply!
Regarding that line: I don't see a
"t=1" refers to iterations, which cryptsetup binds to 4 as minimum by default, which is even better and exceeds the recommendations; not that it's overkill since, as I've stated, the specific RFC recommendation for disk encryption (different from above general recommendation) is 6 GB memory cost and increasing iterations does to some degree allow compensating for lower memory (though if possible, the memory recommendation should be fulfilled before increasing iterations, which the RFC also states elsewhere). So to have argon2id used by Heads either the cryptsetup version needs to be bumped to one from the last 2 years or the pbkdf needs to be supplied with an additional parameter (
Honestly I think that this is still not a good approach at all...it would be much better if at least some random, higher entropy password (e.g. 7 words from word list or ~20 random characters) was generated for each user separately by OEM and delivered by mail (physical with notebook / PC or email), but that's a problem for OEM, not Heads itself, per se.
Maybe I'm misunderstanding what you're saying, but Heads does use weaker settings than what the user has set in the OS in some cases; e.g. I had put a new key into slot 0 from dom0 with argon2id and 2 GB memory cost and then rebooted and done Heads LUKS re-encryption. Here Heads created a new key for slot 0 with argon2i (much weaker) and 1 GB instead of 2 GB (weaker) instead of reusing the parameters of the existing container; if cryptsetup were bumped to a more current version (>=2.4.3) then it would have chosen argon2id, at least.
This is what #1536 is about; I simply described it from my user experience; I didn't check if it was due to any files created, though that sounds plausible.
Awesome feature btw., I'm looking forward to using it! |
@UndeadDevel Not time for a PR yet, but testing things under testing branch https://github.com/tlaurion/heads/tree/cryptsetup_version_bump-reencryption_cleanup and trying to document in commits done there. Note that argonid is not provided by external argon2 library but internal included one (otherwise heavier footprint) and where crypto backend is kernel, not libgrypt (faster hw acceleration provided, lower rando compared to libgcrypt :/) but where urandom is now fed by intel hw rdrand as per #1478 Look at modules/cryptsetup2 Commit: 53aab6f With -B 64 removed with 2.4.3 reencrypted: Slower reencryption speed: stabilizes at 110 mb/s and ETA is misleading. With master https://app.circleci.com/pipelines/github/linuxboot/heads/700/workflows/cd7734e5-5b90-47be-a53b-98bcf1eeed6a/jobs/13596/artifacts rom Commit: Line 5 in 9afe235
cryptsetup 2.3.3, -B 64: Faster reencryption speed, stable at around 138mb/s and ETA not misleading. |
@UndeadDevel so confirmed that on master, reencrypting passes to argon2i |
Houla @UndeadDevel Speeds are way slower under cryptsetup 2.6.1, maybe having to do with new defaults and/or directio This is based on tlaurion@61636a5 |
Same result removing --direct-io on Samsung 860 1TB drive I had lying around with tlaurion@9877d46 Note that speed is slowly increasing, now at 67 MiB/s, but at that speed... But I highly doubt to reach speeds that are supposed to be around 200 MiB/s on those SSD drives normally with master and with TPM DUK and a safe 7 words diceware passphrase. Reencrypting, at this speed, becomes an anti-feature for re-ownership. @UndeadDevel Why reencrypt OEM install if it takes the same time to reinstall fresh? |
This issue is tricky. Let me explain.
@UndeadDevel those are the thoughts i'm having letting the reencryption of the two devices complete and attempt to reencrypt the first one without --direct-io, and the second one with direct-io. Otherwise, we need to acknowledge that newer versions of cryptsetup are taking radical steps enforcing better defaults that should be applied at OS installation (Newer OSes will follow) but as of now, second laptop (1TB drive) was a test install of Qubes 4.2. If Qubes 4.2 has not revised their installation defaults/sector alignments/disk geometry alignements and Heads is having more recent version then OS deploys, we might be better then for our own goods :/
So not sure what to do here but going back to the old thread I opened on QubesOS and try to talk with the experts. Passed my sunday trying to figure out what to do here. Will check results on both drives, test with Otherwise, PR welcome! |
So reencrypting Q4.1 installation resulted into a LUKS container that was still argon2i. I guess that is good. We should not interfere with OS initrd support. This is why reinstallation is needed for non-experienced users once in a while, unfortunately (Q4.0 differs from 4.1 which differs from 4.2 defaults on so many disk layout/pool specs/encryption/trimming behaviors) which affect security/performance/resilience. But that does not explain speed of Q4.2 reencryption speeds. Stopped reencryption. Will reinstall Q4.2 over MX500 drive I have extended comparative info from the past and stick to that for testing. I guess --direct-io is still needed. Will re-add that. |
Regarding the command options: all I know is that I can't find the Regarding (re-)encryption speed: I don't know why it's that much slower with the new version in your tests, but having the option to re-encrypt still makes sense even if slow, e.g. when receiving the device from OEM and not having a good, secure system to create the installation media on: it would be preferable to have a known good install in that case. Furthermore, the main use case for re-encryption seems to be after receiving the machine from OEM; it's not necessary AFAIU to do this for every factory reset, so I don't think it's a huge issue if it is slower; at least for me personally I much prefer it to be slower than less secure. Bumping the cryptsetup version also has other benefits as we've already discussed here. Also I'm a bit puzzled, as on my SSD (Samsung 980 Pro 1 TB) it took less than 15 minutes to re-encrypt (with Nitrokey Heads 2.1)...presumably the LUKS container grows as I put more data on it due to the thin provisioning of next layer (LVM)? Even in that case, speed for me would have been > 200 MB/s (I didn't pay attention to it then and I can't re-test right now; late next week I can test re-encryption again). Lastly, a note on the warning message informing the user of the re-encryption starting (nitpick):
IMHO the proper phrasing would be "new Disk Recovery Key passphrase" instead of "current Recovery Disk Key passphrase". |
@UndeadDevel similar comments from https://forum.qubes-os.org/t/ssd-maximal-performance-native-sector-size-partition-alignment/10189/55 As per latest tests:
Results in reencryption still in online mode of 31 MiB/s. Will open issue on cryptsetup gitlab soon with proper output log. This is annoying. |
I will look up on those in next steps. Thanks! |
Will dig that down and might explain things since kernel on tested laptop (as for most others outside of librems and nv41/ns50) are based on 5.10.5 |
@UndeadDevel continuing attempts under https://github.com/tlaurion/heads/tree/cryptsetup_version_bump-reencryption_cleanup where tlaurion@755c392 version bump kernel from 5.10.5 -> 5.10.201 with board config changes and config changes. |
As for -B or --block-size=MiB, or -b or --size=SECTORS, those are still present under cryptsetup 2.6.1. -data-unit-size replaces -B. Seems like logical size needs to be replaces by physical size. Recommendations are to check smatctl -i output which goes striahgt back about how to deal with the problem as reported to qubes forum [user@dom0 ~]$ sudo smartctl -i /dev/sda
So we have physical sector size of 4096 where logical is 512 and where 2.6.1 is by default using 512 again. I'm getting lost and tired of this rabbit hole. Will regroup and try to figure out how to question this correctly to cryptsetup devels. Seems like we have to override detection here otherwise doing the wrong thing. |
That command doesn't even show me sector sizes on my nvme, but
Might help explain why I've had much better performance... |
Absolutely right there. The only parameters relevant to 2.6.1 are --sector-size=bytes, where 2.7.0 will reintegrate equivalent of -B --block-size=MiB through --data-unit-size=bytes. --use-directio also only applies to luks1. When looking at debug output and disk activity, chunks rewritten to disk are way slower to write to disk than before. This makes me think that something is wrong with configured options. Some internals changed, including sse aes support which is now optional. cryptsetup guidelines say that cpu should not impact much since normally reencrypting is tugging on IO more then CPU, but this is clearly not the case here, at least on 3rd gen cpu like for the x230. Enabling all kernel options for benchmarking cryptsetup as well as adding sse acceleration for aes on argon internal library. Note once again that cryptsetup is compiled to use kernel crypto backend, that internal argon library is used instead of external one (for firmware size footprint) and that libgcrypt is considered slower then the kernel if cpu acceleration is enabled. Also note that cryptsetup uses /dev/urandom here (unless /dev/random specified) where again hw crytpo backed acceleration is activated in kernel config for a while now. Testing new install of Q4.2rc5 and redoing with latest roms with configure option and all interesting crypto in kernel. Continuing https://github.com/tlaurion/heads/tree/cryptsetup_version_bump-reencryption_cleanup with
Agreed but as said.... 26 MiB/s is unacceptable still. That is 2.5 hours to reencrypt disk. Like I said, reinstalling would take less time and defeats the purpose. The tolerance point when this feature was created was that the disk should be reencrypted under one hour. It was actually reencrypted on chosen SSD under 30 minutes before for same disk, same cpu same memory.
nvme and higher end CPU hides the bottlenecks on newer hardware. Unfortunately that won't fly for most users of Heads.
I guess you are talking about the wording of the Re-ownership wizard which matches vocabulary outlined here https://osresearch.net/Keys/#luks-disk-encryption-key The end user is told the context here (passphrase that was setuped at OS installation). You can raise another issue on that one if more unifying/simplification is needed, where PR would be more appreciated. |
Well...as I see it if you don't trust modern hardware at all then your system will soon (next 5-10 years) be unusable anyway; furthermore, if security is the reason for staying with old hardware, which already entails plenty of sacrifices, wouldn't a 2 hour wait be acceptable if it means more security? As I already pointed out, the problem with re-install is that for those who are buying their first secure system it will be difficult to create a trusted USB drive as installation medium, so running re-encrypt from Heads still makes sense here, even if installing were faster; furthermore, re-encryption is not something that normally has to be done very often; in fact, with good opsec practices the main point would be after receiving the device from OEM and setting up the secrets (re-ownership); on further factory resets it can likely be skipped. I can't re-test under Heads right now, but I ran a
Curiously, it reports One might say that this doesn't transfer to Heads as it runs on bare metal, but Heads should really be even faster due to more resources available and no virtualization layers. As stated, a full re-encryption of my ~930 GB LUKS container under Heads took less than 15 mins (albeit with the old cryptsetup version).
I can try to do a PR, but I'm not a professional developer and so far I've only contributed to lower complexity projects, so keep that in mind. I'll try to get to it this week. |
@UndeadDevel Attempts to reencryption speed and discussions on that specific issue under #1541 |
Fell on cloudflare/linux#6 pointing to torvalds/linux@39d42fa last night. Resulting testing works way faster and stabler. Idea there that got merged in Linux kernel is to bypass kernel read and write queues. This best practice needs to be applied to make sure we are applying fastest read/write paths without additional delay and tackle IO limit of bus and SSD only: not testing memory/memcpy/kernel buffers/bus/SSD limits exposed on older platforms. All will benefit. |
It was decided that Heads should not interfere with OS choices, where pushing for better defaults should unfortunately be done upstream in the OS installer hardcoded options. If for whatever reason, you believe Heads should force better encryption options down at Re-Ownership reencryption time, please reopen. Note though that some versions of old hardware don't support hardware accelerated encryption and this is why this choice is not currently enforced. One such example is the x230i. Therefore, detection of hardware specs and hw acceleration features should be done under OSes. At some point I feel I have to draw a line into maintaining things that might break down not properly thought impacts of such improvement requests. I think OSes are doing a proper job at following best practices generally in that matter, where Heads should focus on permitting re-ownership flawlessly, and that enough is becoming complicated. |
@tlaurion The QubesOS 4.2 installer does result in the PBKDF argon2id to be used, however; the problem is that Heads, when doing a container re-encryption, re-encrypts with argon2i due to using an outdated cryptsetup version, though I see that you've added commits to the PR, which I haven't reviewed yet (see my comment there). I understand that Heads maintainers won't necessarily have the resources to be better than OSs like QubesOS (where I've contributed this comment to argue for improved defaults), but I do think that it's a necessity for Heads to provide a more current cryptsetup version to not use the outdated defaults of an older version (which, again, may be fixed in the PR I haven't reviewed yet). It might also make sense to provide the user with the opportunity to choose the memory cost and iteration time; i.e. after the user chooses re-encryption in the whiptail menu or during factory reset, do a One big advantage of this is that cryptsetup, according to the man-page of 2.6.1, by default caps the memory cost at 1GB and may even choose a lower value depending on its benchmark result. Meanwhile the IRTF recommendation is 6 GB, which is above even the current possible (for cryptsetup) maximum of 4 GB; cryptsetup only allows using 4 GB if the parameter If you agree with this I could see about providing a PR to implement it. This, together with a cryptsetup version bump in Heads, and considering that point 3 of the OP was implemented already in #1542, would indeed fix this issue in a sort of second alternative solution. |
Thanks @UndeadDevel . Version bump to 2.6.1 occurs in PR as of now. Will also not bump to 2.7.1 as of now, too edgy and not used by mostly any distro. I tend to not want to have Heads users as beta testers for upstream. I'm also not convinced pushing for SSD enforced live encryption and would delegate reports to people more qualified, or at least until it becomes mainstream and deployed per OS installers. |
Okay great, @tlaurion, so that (cryptsetup version bump) fixes the most pressing issue! I totally agree about not bumping up to 2.7.1. Regarding I'll post your relevant comment portion from the PR thread here to discuss further the encryption parameters:
The thing is, the official recommendations of the people who created Argon2 as well as the IRTF recommendations differ from the personal opinion of the lead cryptsetup maintainer:
So cryptsetup deviates from the recommendations of the people who probably know better by prioritizing iterations over memory, which should not be done for Argon2, especially argon2id and argon2d (even for argon2i it's not recommended, but less bad; overall this doesn't mean we should switch to argon2i, however, as argon2id is still more robust). Also, the hash function SHA512 is recommended by yet other experts for better quantum resistance for So really the problem is with the cryptsetup people, who stubbornly oppose the official recommendations. Ideally they would wise up and change their defaults + implement the possibility of more than 4 threads and more than 4 GB (+SHA512 as the default hash function for aes-xts-plain64). I can understand if you want to say "upstream issue, not going to touch it", but IMHO it would be nice if the IMO most severe limitation of current cryptsetup defaults (memory cost capped at 1 GB in default benchmark mode) would be (partially) mitigated by allowing the user to choose the memory cost, which we would feed into the And yes, I agree that this isn't really an issue for the TPM DUK (here the question is rather how securely the passphrase is stored in the TPM), but it is an issue for the LUKS DRK, which Heads also changes during OEM Factory Reset. The user will not be remembering 256 random characters for the LUKS DRK, after all. (Hopefully last edit:) Okay I did some more experiments on file-based LUKS containers with cryptsetup 2.6.1 in a large Qubes Standalone VM with 10 GB of RAM and the whole CPU (12th gen i7); the following command will produce what I would call the currently best possible (with cryptsetup 2.6.1 and that, or better, hardware/vmware setup) settings:
and as you see from the command only 5 seconds unlock time, which is acceptable UX-wise. Of course on older hardware this will not be possible, unless the user accepts a lot more than 5 seconds or lowers the memory cost (cryptsetup does not allow going lower than 4 iterations sadly, even though that would be better for argon2id than lowering the memory cost). |
@UndeadDevel Everythig needed under #1541 ? |
Is your feature request related to a problem? Please describe.
Describe the solution you'd like
I think probably the best solution would be to read out the parameters currently used for that container (
luksDump
) and then either re-use them or prompt the user, telling him the current parameters and whether they are outdated (e.g. pbkdf2 instead of argon2 being used; memory cost too low, e.g. <2 GB if argon2 is used; argon2 being used in weaker variants, i.e. not argon2id). Maybe the user could also be prompted for the iter-time (-i=milliseconds
parameter; default is2000
), so that the users can choose their own security / convenience tradeoff, especially since the recommended 6 GB memory are currently not possible with cryptsetup (see "Additional context").Describe alternatives you've considered
An alternative that is still better than the current situation would be to use stronger defaults, at mimimum argon2id with 2 GB memory cost (and iter time of >=2000, but 2000 is already the default with LUKS2).
Additional context
Do note that currently cryptsetup seems to only support a memory cost of up to 4 GB and parallelity of 4. It will also treat those two parameters (
--pbkdf-memory=numBytes
and--pbkdf-parallel=numThreads
) as a maximum; a parallelity of 4 is used as default by cryptsetup; should the system for some weird reason have e.g. less than 4 GB available while 4 GB are given as the parameter or fewer than 4 cores, then cryptsetup will lower the actual parameters used.The text was updated successfully, but these errors were encountered: