Repository navigation
Minimum modulus size #445
Description
Activity
See also: #350
For testing and supporting existing implementations I don't think a blanket limit makes sense.
But maybe a default generator that limits the range would be helpful for newcomers.Reacted by Mateusz Kramarczyk and teknalb- Not supporting existing implementations which would require this is a benefit. RSA 1024 and even 2048 are plenty fast for testing.…On August 9, 2024 11:00:27 PM GMT+01:00, Friedel Ziegelmayer ***@***.***> wrote: For testing and supporting existing implementations I don't think a blanket limit makes sense. But maybe a default generator that limits the range would be helpful for newcomers.
Not supporting existing implementations which would require this is a benefit.
I am glad for you that this is how you can run your projects, it is not the same for all of us.
Reacted by biørn, Tom Hebb and teknalbI agree with @ryancdotorg and with the rationales outlined in the Go proposal.
I also note that the
rsacrate already enforces limits on key sizes, specificallyRsaPublicKey::newwhich returns an error for any key larger than 4096 bits. This method has a trapdoor for configurability viaRsaPublicKey::new_with_max_size.An intermediate pathway would therefore be to do the same thing for minimum sizes:
- Have the default pathway enforce a secure minimum size in
RsaPrivateKey::newandRsaPublicKey::new, which we can increase as necessary in line with best practices. - Have a trapdoor for configurability via e.g.
RsaPrivateKey::new_with_insecure_key_size, which enables reviewers to clearly identify codepaths that are insecure in production.
Then the question of whether to expose the insecure / hazmat configuration APIs at all can be separated from the "stop people shooting themselves in the foot because they think they are getting 256-bit security" issue.
- Have the default pathway enforce a secure minimum size in
For reference, here's an example of use of 512 bit RSA that could have damaged a power grid:
It's been known to basically worthless in terms of security for decades, let it die.
Mis-use resistance would be good - similar with x25519-dalek we added static_secrets opt-in to track it's use.
One way would be to split the constructor for insecure and secure constructions - the insecure constructor for given bit-lengths would be hidden behind a feature - however later on how this whole thing evolves through time requiring approach to avoid breaking changes.
By having to use a feature (or cfg) to override mis-use resistance it could be potentially tracked in at least feature usage - now it is non-trivial (still possible but hard to maintain to track it's use) to find any direct dependencies which use insecure sizes - where as using a feature it can be tracked through analysing crates.io-index that exposes the used features.
When we put
static_secretsfeat to x25519-dalek, I found several cases of where people were using it wrong.If we take this to extreme - there could be even a crate with all the possible keysizes as marker types and the type only gets used through feature / cfg and then features can track which keysizes are supported.
e.g. marker type could be categorised as known "minimums" with the size embedded in data-enum
BITS_2048(...)🤔Also according to some literature 2048 bits is considered obsolete by 2030 - should this be taken into account ? Having this evolution built in without inducing breaking changes when the inevitable factorizations happen - tick tock.
So for this reason I would say having "well known minimums" categories as types could be ok for future backward compat w/o having to do breaking changes allowing depreciation of surface that leads to insecure constructions.
I strongly disagree with this restriction the library should remain as flexible as possible; modulus size is a user's choice.
As an alternative I'd suggest informing the user with a warning or something if the key size is known to be broken.Reacted by Mateusz Kramarczyk- Extensive empirical evidence shows that users of cryptographic libraries are frequently not qualified to make choices on things like modulus size. Putting broken (< 1024 bits) and weak (< 2048 bits) behind feature flags seems like a good solution, and type annotating by size is an interesting idea.…On August 15, 2024 1:01:59 PM GMT+01:00, teknalb ***@***.***> wrote: I strongly disagree with this restriction the library should remain as flexible as possible; modulus size is a user's choice. As an alternative I'd suggest informing the user with a warning or something if the key size is known to be broken.Reacted by Carl Winbäck, teknalb, Jack Grigg and Joe Birr-Pixton
a feature flag for broken/weak sounds good idea without sacrificing flexibility :)
I'll +1 @str4d's suggestion that we should follow what we already do with
RsaPublicKeyand have checkedRsaPrivateKeyAPIs with short, convenient names which enforce a minimum modulus, and parallel unchecked APIs with longer names that don't enforce the restrictionReacted by Friedel Ziegelmayer, teknalb and Alexander Kjäll@tarcieri Is there any way to do this without adding to this as a fully fledged feature? Maybe some kind offn modulus_size(&self) -> usizethat will allow us to check thatkey.modulus_size() >= 3072?EDIT: It is possible via the PublicKeyParts trait, like so:
key.n().bits()Reacted by Tony ArcieriI made an attempt at this in #526 but it's breaking the majority of current tests
Fixed them in #561 (by increasing key sizes)
All tests complete in 5 mins now so pretty much the ~same :)
Units are all 1024/2048 with no difference in speed
However proptests are gated under
feature=hazmatnow usingRSAPrivateKey::new_uncheckedw/ 512bit key to save our CI- added a commit that references this issue
on Sep 21, 2025 - added 2 commits that reference this issue
on Jan 27, 2026
RSA is catastrophically weak with 512 bit keys, and anything less than 2048 bits is insecure. A minimum key size should be enforced. Golang has proposed to require 1024 bits minimum:
golang/go#68762
however 2048 would be a good choice where backwards compatibility requirements are minimal