AES in CTR mode?
Hello!
I'm considering using ring for a project, but I require AES CTR 128. It looks like the boringssl code for this is being compiled, but I can't find any reference to it in the Rustdocs. Is this being exposed by ring in any way? And if not, are there plans for this?
Thanks! Sergio
What construct are you trying to implement on top of AES-CTR? If it's AES-CTR-HMAC-SHA-{256, 384, 512}, we can definitely explore adding that construct to ring. If it's a (userspace) AES-CTR PRNG then we could definitely explore adding one of those too. Or maybe it's something I'm overlooking?
Regarding the BoringSSL code, we removed the AES-CTR C code with the intent that, if we were to do something with CTR mode in ring, we'd do it in Rust instead of C. I believe it would be easy to do, especially after #369 is done.
It is indeed a PRNG.
Out of curiosity, why not expose AES-CTR directly?
Out of curiosity, why not expose AES-CTR directly?
ring tries to expose crypto at a level of abstraction that is (far) higher than cipher modes, in an attempt to minimize mistakes in usage of our APIs.
For example, let's say we want to support applications that use AES-128-CBC-HMAC, and we want to use a userspace PRNG to generate the CBC IV to avoid syscall overhead. In that case, we wouldn't expose AES-CBC or the PRNG. Instead we would expose some kind of "AES-128-CBC-HMAC-SHA-{256, 384, 512}-with-IVs-generated-using-a-userspace-PRNG" AEAD-ish interface, which would be roughly equivalent in safety to our AES-GCM and ChaCha20-Poly1305.
It is indeed a PRNG.
I hope the previous paragraph demonstrates why it's useful to be as specific as possible in what you need so we can figure out exactly what to add.
What are you planning to use the PRNG for? And why doesn't ring::rand::SystemRandom work well enough for that use case?
Thanks for taking the time to share.
Thank you for the generous response. :)
I'm using the PRNG to generate deterministic random numbers, given a seed, as a component of a the generation of a hash value. Because the numbers need to be deterministic to recompute the hash in the future, SystemRandom does not suffice.
OK, I'm going to close this, but not because I don't want to help you. Rather, this is just outside the scope of what we're trying to do in ring. But I am open to adding a higher-level feature that you can use, if it is needed and if it would be generally useful.
I don't have any plans to add any "deterministic PRNG" feature to ring, except maybe in the testing module, ring::test, where we already implement multiple deterministic implementations of ring::rand::SecureRandom for testing purposes only. I don't know of any real-world protocol that uses a deterministic PRNG construct. However, maybe I'm overlooking something. If so, please file an issue about adding a deterministic PRNG to ring.
It sounds like what you want is more of a KDF (key derivation function) than a PRNG. We already have a KDF implementation in ring::hkdf that is quite good. If you don't need specifically AES-CTR then I recommend you use that. If you need an AES-CTR-based KDF then please file a new issue with more details about the motivation (i.e. which protocol you're implementing).
Thanks!
Sorry, but I explicitly need AES-CTR 128. I'm not using it as a KDF.
I was under the impression that ring would serve as a replacement for, as an example, openssl's crypto primitives. Is that not the case? Based on what you're saying, your intent is not for ring to be used as a bag of crypto primitives, but instead, as a set of fully constructed crypto functions, similar to libsodium.
similar to libsodium.
ring will probably be even more high-level than libsodium, according to the current plans. That's why I redirect feature requests to be for higher-level things, not the low-level primitives.
Just want to mention that, theoretically, crypto libraries can be both high-level and low-level. To protect and guide users, the two parts should have telling names like "recipes" and "hazardous materials" (see https://cryptography.io/en/latest/).
On the other hand, since BoringSSL stripped a lot of functionality, ring might not be in the best position to provide all needed primitives. And ring is rather new, so the focus right now is probably on the "recipes" part. And I'm sure @briansmith has a couple more good reasons?
In general, I am very open to adding functionality that people need into ring. But at least for now, I encourage one way and discourage the other way.
Here's the way I discourage: I need to do something. The minimal thing to add to ring needed to do that is Y, so I'll ask for Y to be added to ring so I can implement the rest of the construct outside of ring.
Here's the way I encourage: I need to do something. I'll add a misuse-resistant way of doing that to ring.
Let me given an example:
Some people want to implement Noise protocols using ring, and I want to encourage them to do so. Noise usually uses a combination of static and ephemeral Diffie-Hellman. ring currently only supports ephemeral Diffie-Hellman. So, we need to add something to ring:
The discouraged way: Add a static Diffie-Hellman API to ring.
The encouraged way: Add a hard(er)-to-misuse ephemeral-static API to ring. Maybe this requires putting X3DH and other ephemeral-static Diffie-Hellman constructs directly into ring, but I hope instead there's a more general safe(r) construct on top of which X3DH and other things can be implemented.
In terms of what @Philipp91 mentions, ring does have a "hazardous materials" API already, but it is intentionally restricted to internal use within ring.
Another way of thinking about this is that ring is a framework for implementing useful and interoperable crypto protocols, not a framework for implementing crypto primitives.
Also, if you need a feature added to ring and you don't want to publicly talk about your use case(s) in detail (e.g. because your project isn't open source), you can always email me at [email protected] and I'll explain how that works.
Thanks again for the thoughtful reply.
While I believe I understand where you'd like to go with ring, I propose that you take measures to make this more explicit. The ring API is currently nowhere near as high-level as libsodium, for instance. libsodium rarely exposes algorithm details, but ring gives me direct access to things like PBKDF2 and SHA*. Why not hide these? Based on your heuristics, if I feel "I need to get a cryptographic hash value," ring shouldn't answer with: "choose from these hash functions," but instead, provide some very-high level hashing API, likely with different variants, depending on the input and requirements. libsodium does just this, for instance.
Best of luck with ring! I was hoping ring would be the answer to crypto in Rust, but unfortunately, it looks like it will only be one part of the story.
@SergioBenitez I saw your PR for the cookie-rs crate. Did you want AES-CTR for use in that crate, so that you could implement AES-CTR-HMAC-SHA256? If so, I'd be happy to accept a PR to ring that implements an AES-CTR-HMAC-SHA256 AEAD using the same API as AES-GCM.
I also have a need for direct access to AES CTR and ECB.
I understand your argument of "expose higher level constructions, not primitives", but in this case these are simply files encrypted using AES-CTR. It is not used as part of a higher construct. I'm currently using rust-crypto, but I'd like to transition all my crypto to ring.
Since this is based on reverse engineering, I also have cases where AES is used in ECB or CTR modes as part of some higher level construct, but I've only been able to replicate it without identifying it.
Would you consider adding a primitives module, with a big warning redirecting users to the high level constructs ?
@plietar In the case of https://github.com/plietar/librespot/blob/d940ed161a0d026d293275f6cfc28c32fada2880/src/authentication/discovery.rs#L130, isn't that AES-CTR-HMAC? Also, in the case of https://github.com/plietar/librespot/blob/d940ed161a0d026d293275f6cfc28c32fada2880/src/authentication/mod.rs#L91, isn't that AES-192-CBC?
Right now we have to concentrate on improving the really good crypto that we want to become ubiquitous, and there's no time available for obsolete and/or proprietary crypto and/or unusual crypto.
I re-opened this. If somebody wants to work on a public API for AES-CTR, I am open to accepting that change.
ring already has AES-CTR implemented in aead::aes. In order to implement AES-CTR with 96-bit nonces and 32-bit counters, we'd basically just need to:
- Copy-paste
aead::aes_gcmto a newaesd::aes_ctr32. - Remove the GCM-related bits from
aead::aes_ctr32. - Expose
aead::aes_ctr::Keypublicly. - Write integration tests for the new
aes_ctrAPI, intests/aes_ctr_tests.rs. There are probably test vector files from BoringSSL that we can use for this, copy-pasting from another similar test.
If/when we have a public API for AES-CTR with 96 bit nonces, it might also make sense to replace the direct uses of aead:::aes in aead::aes_gcm with use of the new public API.
Also, above, I mentioned aead::aes_ctr32 as the module name. But it shouldn't be a submodule of aead:: since it isn't an AEAD cipher. Also, if/when aead::aes is used outside of aead::aes_gcm, aes should be moved out of aead. I will investigate doing this now.
Follow up to https://github.com/briansmith/ring/discussions/2414#discussioncomment-13120917.
It would be good to write up an outline of your planned approach, e.g. whether 96-bit nonces and 32-bit counters are sufficient or whether you intend to support larger counters, if/how the AES-GCM code and AES-CTR code will avoid duplicate logic w/o regressing performance of the AES-GCM code, how you will test it, the proposed API, etc.
For our use case we need a 96 bit nonces and 32 bit counter see here so I'd go with that.
Implementation wise I'd follow approach you propose here, create aead::aes_ctr32 (or aes::aes_ctr32) and move ctr logic from aead::aes_gcm into it to avoid code duplication. I'm not sure what performance pitfalls are here, but I'd rather duplicate part of the codepath if needed.
Migrated codepath (used by GCM) will be tested by existing GCM tests. New codepath would be covered with new tests and with BoringSSL tests.
As for the proposed API I'd look into approach aws-lc-rs took.
My colleague already worked on this, but currently has other priorities so I'll try to take over .
If there's no objections I'll try to open a draft PR next week
I'm not sure what performance pitfalls are here, but I'd rather duplicate part of the codepath if needed.
The AES-GCM implementation has benchmarks that you can run to verify there are no performance regressions.
The AES-GCM implementation does check for 32-bit counter overflow at the start of each seal/open operation. This overflow check needs to happen for the separate AES-CTR implementation too, probably by duplicating it there.
New codepath would be covered with new tests and with BoringSSL tests.
I think this makes sense. It is important to have tests for the counter overflow case. Since that involves inputs/outputs that are too large to use as test vectors, I recommend you look at the test at the bottom of aes.rs.
One thing that isn't obvious is that aes_gcm.rs implements single-block AES encryption by converting the block to a counter and then AES-CTR encrypting the all-zero block with that counter.