-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Chacha20-Poly1305 encryption #14249
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
base: master
Are you sure you want to change the base?
Chacha20-Poly1305 encryption #14249
Conversation
be24166
to
22644d4
Compare
Last push has support for FreeBSD, which is very straightforward because all the crypto code is already available in the kernel. Importantly, I've done a interop test: a pool with a |
I appreciate very much you made it part of ICP, it means nearly no work needs to be done for me. |
So, what's the next step for this? If its just waiting until volunteers have time to review, no problem, I get it! If there's something I could do or need to do though, I'd like to get on to that. (Should I be dropping in on the monthly call to talk about it?) |
Yes. There are a number of PRs waiting review and reviewers have limited bandwidth to look at them. Larger PRs like this take substantially longer to see review.
That might help attract reviewers. |
Hey there, I must admit I'm a little bit confused here. Linux has already support for Chacha20Poly1305 under lib/ and relevant arch/, why do we need another implementation? |
@evrim there's two ways to look at it. One is that Linux's crypto code is only available to GPL kernel modules, which OpenZFS is not. The other is that by doing it in the ICP, other ICP-using ports of OpenZFS (Windows and macOS) can use it. |
@jittygitty there's no code in ZFS right now that can call into the kernel crypto API, regardless of how you build it - you will always be using the ICP for crypto even for AES modes. You'd need a variant of zio_crypt for that, which is well outside the scope of this PR. |
We talked about this at the 31 Jan call. Feedback was generally favourable, thanks all! I was waiting to check my notes against the recording but that hasn't surfaced yet and I want to get moving on this a bit this week. So here's what I wrote down. If it turns out I got something wrong, I will of course adjust it.
Finally, and most importantly, it was agreed that this is obviously a nice feature, but if no one else wants it then perhaps it we shouldn't be taking on the maintenance burden. I will soon go and try to get a rough show of hands to see if anyone would else would use this. Probably, a carefully-worded query to the mailing list, discussion forum and reddit, and go from there. I'll return this to draft status for the moment, and add some additional todo items to the top post. |
I find this feature usefull and would help with this PR if you want. There is also a rfc7905 which update TLS / DTLS with ChaCha20-Poly1305 - so why should OpenZFS not go with the time and have this option. |
I did all the testing I wanted to do with a view to adding a feature flag. I created a new pool on Linux with master 620a977 + this PR, exported it, then rebuilt on master alone and imported the pool. All the encryption properties are returned except for
This appears to be because the underlying value is out bounds for this enum, so the default ( Attempting to load the key fails, in a slightly weird way:
and of course it can't be mounted:
I say it fails in a slightly weird way, because I think its just lucky this time. If we're compiled with
When asserts are disabled, it seems like its only doing ok because the crypto table entry does actually exist for I do think that behaviour is lucky. For the next new cipher suite So probably this alone is enough to suggest a feature flag is warranted. |
I did further send/receive testing as well. When sender and receiver both support chapoly, it works exactly as it does for AES - raw send doesn't require the dataset loaded on the sender, not-raw does. All fine. When there's no chapoly support, raw send still works. A stream is produced, and if that's later received to a chapoly-supporting pool, it goes in just fine, key can be loaded and it can't be mounted. Importing a chapoly stream into a pool with no support fails:
Its not totally clear to me without looking inside that that's indicating. Presumably, invalid property of some sort. I'll check more closely tomorrow. But again, likely the a feature flag is going to benefit. |
@mcmilk sorry I missed this! Thanks! At this point I don't think there's much else to do other than as much code review as we can. The main thing I want to feel good about is that I'm not misusing the crypto stuff in some important way. General bugs would be bad but survivable, but the crypto being no good is worse than not having it at all. I think its probably fine, but if you've got good ideas that'd be great. |
Ehh, I've got my brain in backwards this evening. A feature in the dataset isn't going to make an old implementation magically able to cope with it. That said, I'll see if I can do something now to help for the next new crypto algorithm. |
Last push updates Monocypher to 4.0.2, adds a test to ensure replication streams with encrypted datasets are accepted or not depending on whether or not the feature flag is set, and collapses it down into a single commit. The CodeQL failures at the same as the ones we saw right at the beginning, and are safe. @behlendorf how do you feel about this nearly a year on? :) I don't think there's any more to do. |
Did anyone thought about wireguard zinc implementation like in comment: #8679 (comment) Today we will only have implementation which don't use vector extensions targeted only at raspbery pi like devices :( |
Hi, thanks for working on this! I decided to try this out on a Raspberry Pi 4B (4 core, 4 GB RAM) and a 1 TB HDD connected via a USB enclosure. One issue though, I noticed I'm only getting about 30 MB/s read speeds and massive amounts of CPU usage. I can get 100 MB/s write speeds just fine (and this matches the speed of the chacha20 Rust crate without neon). Without any encryption, I get 150 MB/s write and 170 MB/s read. Upon further inspection, it seems to be because of the massive amounts of messages in dmesg. I don't get them with AES-256-GCM though.
|
@ErrorNoInternet thanks for the report! I've pushed a small change that should at least deal with the log spam. |
Nice! Getting stable 110+ MB/s read speeds now :) Thank you! |
Great to know, thanks :) |
a972fb9
to
e270db8
Compare
What's keeping this from being merged? I'm looking forward to it, since it's extremely useful for devices that meet the RAM requirements for ZFS but don't have CPUs with AES instructions/acceleration. |
@rsalvaterra still intended, just hasn't been anywhere on my radar for a good long while. I've just rebased it to master, though barely any testing done. I wouldn't want it merged as-is though, at minimum I want to do a full read through and make sure I still like everything in it given everything I've learned about OpenZFS internals since I first wrote it. |
Last push removes the test vectors and runner in favour of a proper test set from the Project Wycheproof, matching what we have for AES-CCM and AES-GCM. |
I'm setting this to draft for the moment. It works, but for the moment I'm very uncomfortable about making the on-disk format change until I have chance to do some more cleanup work on the crypto code and infrastructure. I'll continue using this PR as something of a testbed for that. |
Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <robn@despairlabs.com>
This commit implements the Chacha20-Poly1305 AEAD from RFC 8439 as a new algorithm option for encrypted datasets. AES (and particularly the default AES-GCM mode used in OpenZFS) is known to be very slow on systems without hardware assistance. There are many such machines out there could make good use of OpenZFS, especially low-cost machines and small boards that would otherwise make very nice storage machines. The Raspberry Pi series of machines are a good example. The best option for these systems is an encryption option that performs well in software. Chacha20-Poly1305 is the current "standard" option for this in many contexts, and is a good choice for OpenZFS. The core Chacha20 and Poly1305 implementations are taken from Loup Valliant's Monocypher. These were chosen because they are compact, easy to read, easy to use and the author has written extensively about its development, all of which give me confidence that there are unlikely to be any surprises. I've added a KCF-style module to the ICP to implement the AEAD. This implements just enough for OpenZFS, and is not suitable as a general-purpose KCF for Illumos (though it could be the starting point for one). For FreeBSD, which does not use the ICP, I've instead hooked it up to FreeBSD's builtin crypto stack. The rest is adding an enabling property value and a feature flag and and hooking it up to all the right touch points, and documentation updates. The existing tests that cycle through the possible encryption options have been extended to add one more. I've added a test to ensure that raw receives of chacha20-poly1305 datasets do the right thing based on the state of the feature flag on the receiving side. There's also a test unit that runs the test vectors in RFC 8439 against Chacha20, Poly1305 and the AEAD in the ICP that combines them. This is most useful as a sanity check during future work to add alternate (accelerated) implementations. Finally, manual interop testing has been done to confirm that pools and streams can be moved between Linux and FreeBSD correctly. Light and uncontrolled performance testing on a Raspberry Pi 4B (Broadcom BCM2711, no hardware AES) writing to a chacha20-poly1305 dataset was ~2.4x faster than aes-256-gcm on the same hardware. On a Fitlet2 (Celeron J3455, AES-NI but no AVX (openzfs#10846)) it was ~1.3x faster. Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <robn@despairlabs.com>
Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <robn@despairlabs.com>
Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <robn@despairlabs.com>
I’ve added a new encryption option to OpenZFS,
chacha20-poly1305
, which implements the Chacha20-Poly1305 AEAD described in RFC 8439. I’m interested in feedback, code review, testing and benchmarking from anyone interested in such things!Important note: I have no particular skill in math, cryptography or secure software. I’m as confident as a reasonably good programmer can be that this is right, but I wouldn’t go trusting your secrets to this just yet!
Closes #8679.
Rationale
AES (and particularly the default AES-GCM mode used in OpenZFS) is known to be very slow on systems without hardware assistance. There are many such machines out there could make good use of OpenZFS, especially low-cost machines and small boards that would otherwise make very nice storage machines. The Raspberry Pi series of machines are a good example.
The best option for these systems is an encryption option that performs well in software. Chacha20-Poly1305 is the current “standard” option for this in many contexts, and is a good choice for OpenZFS.
More information about the rationale can be found in Google’s work on Adiantum (though their solution is necessarily different because unlike OpenZFS it operates on whole disk blocks).
Implementation
Core algorithms
I’ve taken the “core” Chacha20 and Poly1305 implementations from Loup Vaillant’s Monocypher. They are small and easy to read and understand, and the author has written extensively about its development and in particular the mistakes made along the way, which (at least to me) inspires confidence in the implementation.
I considered a number of other implementations, including those in Sodium and OpenSSL as well as a number of other smaller implementations. Despite the relative simplicity of the algorithms, there is lot of variability in the overall quality and usability of different implementations, so I opted for the most straightforward ones I could find.
ICP/KCF module
I’ve written a new KCF-style module for the ICP, that implements the AEAD (the “construction” that binds the cipher (ChaCha20) and authenticator (Poly1305) together) and the glue to make it available to OpenZFS proper.
Illumos does not currently support these algorithms, so it wasn’t possible to just take one from there. I’ve implemented a module, however it only implements what OpenZFS needs and is not sufficiently general-purpose to contribute back to Illumos. I have no plans to do this.
The rest of the module is as simple as I could figure out how to make, especially in some of the buffer management which is quite complex in the AES modes.
Tests
I’ve added a test program that runs the test vectors in RFC 8439. For Chacha20 and Poly1305 this is mostly a basic sanity check to assist in the future with possible alternate implementations (eg hardware-accelerated versions), as there are many implementations out there that have surprising quirks even when used correctly (most commonly endianness problems).
There’s also a full module test, checking that the AEAD is constructed correctly (again using the test vectors) and also makng sure the ICP module interface works.
The tests are only there to confirm basic operation; they have nothing to say about security properties or correctness.
Performance
I have only done very light performance tests to gain a rough idea of how much “better” or “worse” this is than
aes-256-gcm
on a handful of machines I have here. I do not know how to drivefio
very well and I did not make much effort to control variables like other programs running on the machine, so I will not defend these numbers very hard. I’ve run them enough times to be reasonably confident they’re not wildly off the mark.Method and fio output: https://gist.github.com/robn/4b40251ba84728cf8e669649ce77ad56
(ChaPoly in software coming so close to AES in hardware makes me think there’s probably still optimisation opportunities in the AES code, but I have not really considered this even a little bit).
Other notes
This is only for Linux right now. It should be straightforward to implement for FreeBSD too, which has the necessary crypto primitives available in the kernel. I will try to add that soon.Now with FreeBSD support.Related to that, I have not fully updated the tests yet because I don’t want to them to break any automatic PR test stuff that might run on FreeBSD.Done.TODO
After discussion in monthly call:
encryption
propertyFuture work
Just stuff I thought about along the way that I’m not committing to but might like to look at in the future.
icp_aes_impl
andicp_gcm_impl
).zio_crypt.c
up to be common to all ports, with a much smaller layer that calls down to OS-provided cryptographic functions or uses the bundled ones where the system doesn’t have something available. That’s not just for Linux, but would help in (for example) Illumos, which has AES in the kernel but not ChaPoly. I’d probably wait to see what the Windows and Mac ports look like when they’re finally merged before considering this seriously.Types of changes
Checklist:
Signed-off-by
.