-
Notifications
You must be signed in to change notification settings - Fork 119
Generate p and q of exactly half the number of bits of N #98
Description
Currently, several functions in rsa.key have an accurate flag that signifies that the number of bits
should be precisely adhered to. In particular, new_keys and gen_keys have such a flag, which default to True. In the respective documentation, I read the following fragments:
:param accurate: when True, ``n`` will have exactly the number of bits you
asked for. However, this makes key generation much slower. When False,
`n`` may have slightly less bits.
:param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and
``q`` will use ``nbits/2`` bits.
When I call gen_keys(2048), I am presented with an n of 2048 bits, as expected. However, I receive a p of 1088 bits, and a q 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 calling find_p_q(nbits // 2, getprime_func, accurate) (which, for my call, comes down to find_p_q(1024, rsa.prime.getprime, True)). This function contains the following documentation (suddenly none of which promises a p and q of 1024 bits, although the nbits parameter does imply it).
The resulting p * q has exacty 2 * nbits bits, and the returned p and q
will not be equal.
:param nbits: the number of bits in each of p and q.
:param accurate: whether to enable accurate mode or not.
I think it's important to:
- explicitly and clearly document the behavior that users can expect;
- offer a way to generate
pandqof 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;- do this in a secure way, i.e. still choosing primes that are far enough apart.
Note that while PKCS#1 does not require p and q 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 and q have these lengths, as find_p_q contains the following snippet:
# factor n.
shift = nbits // 16
pbits = nbits + shift
qbits = nbits - shift
Combining this with the fact that rsa.prime.getprime simply applies rejection sampling to find a prime of exactly nbits quickly explains why I'm seeing 1088-bit and 960-bit primes.
However, as the comment notes, simply sampling p and q 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 of p and q, 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.