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
Generate p and q of exactly half the number of bits of N #98
Comments
Good comments, thanks. |
This is a misconception. Current state of the art suggests choosing P and Q at random from the range of n/2 bit primes. This guarantees with overwhelming probability that P and Q will be "far apart enough" for the key to be strong. Fips 186-4 has additional requirements:
The strong prime and provable prime requirements are not really nessesary. To quote a 1999 paper
This hasn't changed. So implementing the additional checks isn't necessary. (OpenSSL doesn't do them) On the other hand the I have a working code with fixes for this and performance improvements for key generation. Unfortunately, this is my first git contribution. Still figuring out the work flow. |
@RichardThiessen thanks for the FIPS 186-4 reference. I'm working on an implementation. It's working pretty well, except the multiplication by |
This commit implements the FIPS 186-4 recommendation for lower & upper bounds on p & q, and on a minimum distance |p-q|. @joostrijneveld and @RichardThiessen I'd appreciate your eyes on this before it's pushed to master. If you can, please test & give me some feedback on #98.
7c2468e on branch https://github.com/sybrenstuvel/python-rsa/tree/issue-98-fips-186-4-prime-selection implements the FIPS 186-4 recommendation for lower & upper bounds on p & q, and on a minimum distance |p-q|. @joostrijneveld and @RichardThiessen I'd appreciate your eyes on this before it's pushed to master, as it's of course really at the core of the library. If you can, please test & give me some feedback here. |
I'm afraid I'm currently not in a position where I can contribute or comment, but I'll gladly have a look in a couple weeks (i.e. mid-September). I've set a reminder :) |
Thanks for the heads-up! I'll see about releasing 4.1 before that time then, and then this can go into 4.2. |
The trick for doing approximate multiplication or division of big integers by sqrt(2) (or other constants) is turning sqrt(2) into a fractional constant of the form Then one simply does an integer multiply and divide by the two values (a,2^n) and the result is very close to the correct value. There are a few caveats but they can mostly be ignored: Neither of these really matter though since the space of primes we choose from is very large the precision of the constant (in bits) determines the error and thus a 128 bit constant with error in the wrong direction leaves only a tiny slice of the resulting range outside the correct range. Still, it's good practice to at least pay attention to point 2 above and use the right rounding on the constant depending on the desired direction of error. Here a snippet of find_p_q() from my local heavily modified branch. That should be all you need. ` #constraints implemented are from FIPS 186-4 appendix B-3.1.2
Note that the constant and the result are rounded up to puch the result closer to 2**nbits so we're definitely within the target range. I think it also works on small numbers too. *(checks) Yup, looks like it does work on small numbers (IE:result=ceil(n/sqrt(2)) for n< ~2^128) for testing a hypothetical |
This is about the smallest change I could make to fix the issue. The Also worth noting, I refactored the code in |
Currently, several functions in
rsa.key
have anaccurate
flag that signifies that the number of bitsshould be precisely adhered to. In particular,
new_keys
andgen_keys
have such a flag, which default toTrue
. In the respective documentation, I read the following fragments:When I call
gen_keys(2048)
, I am presented with ann
of 2048 bits, as expected. However, I receive ap
of 1088 bits, and aq
of 960 bits (these values are constant across runs; I'll get to that later).When I then inspect the internals of
gen_keys
, I notice that it's callingfind_p_q(nbits // 2, getprime_func, accurate)
(which, for my call, comes down tofind_p_q(1024, rsa.prime.getprime, True)
). This function contains the following documentation (suddenly none of which promises ap
andq
of 1024 bits, although thenbits
parameter does imply it).I think it's important to:
p
andq
of exactly half of the size of the modulus, for compatibility with other implementations. In particular hardware-based implementations that rely on private keys in CRT form often have this constraint;Note that while PKCS#1 does not require
p
andq
to have a bit-length half the bit-length of the modulus, FIPS 186-4 does require it (Appendix B3.1, top of page 53) by requiring\sqrt(2) * 2^{n/2 - 1} < p < 2^{n/2} - 1
.Upon closer inspection, it quickly becomes clear why
p
andq
have these lengths, asfind_p_q
contains the following snippet:Combining this with the fact that
rsa.prime.getprime
simply applies rejection sampling to find a prime of exactlynbits
quickly explains why I'm seeing 1088-bit and 960-bit primes.However, as the comment notes, simply sampling
p
andq
to be 1024 bits each could result in them being very close together (although I'm not yet sure of the precise requirements and/or statistical properties). I realize this issue is not as trivial as it may sound based on the title. Maybe FIPS 186-4 provides sufficient handholds to come to a secure and bit-accurate generation ofp
andq
, though.If you have ideas about what the API should look like (should the FIPS 186-4 behavior just be default for
accurate=True
?), let me know - I may spend a moment to try to address this.The text was updated successfully, but these errors were encountered: