-
Notifications
You must be signed in to change notification settings - Fork 117
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: