🌐 AI搜索 & 代理 主页
Skip to content
This repository was archived by the owner on Apr 20, 2025. It is now read-only.
This repository was archived by the owner on Apr 20, 2025. It is now read-only.

Generate p and q of exactly half the number of bits of N #98

@joostrijneveld

Description

@joostrijneveld

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 p and q 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;
    • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions