Danger

Nothing here should be used for any security purposes.

  • If you need cryptographic tools in a Python environment use pyca or PyNaCl.

  • If you need efficient and reliable abstract math utilities in a Python-like environment consider using SageMath.

RSA Key Generation#

This page describes some of things that are part of the toy_crypto.rsa module. They are imported with:

from toy_crypto import rsa

Not every pair of primes, \((p, q)\), is suitable for creating a good PrivateKey. With public modulus \(N = pq\), and public exponent, e, some of the conditions that should hold of them are

  • They should be large enough so that N is the desired bit size;

  • They should each be not much less then \(\sqrt{N}\);

  • But they shouldn’t be too close to each other, either;

  • The totient of N must be relatively prime to the public exponent, e. That is \(\gcd(p - 1, e)\) and \(\gcd(q - 1, e)\) must each be 1.

The prime generation function defined in appendix A.1.3 FIPS 186-B [NIST, 2023] guarentees those conditions are met. It is clever in that it checks those conditions on candidate primes before testing whether those candidates are prime, which is a much more computationally expensive test.

The algorithm defined in §6.3.1} of NIST-SP-56b [NIST, 2019] imposes the additional condition that the secret decryption exponent, d, of a private key is not less than \(\sqrt{N}\).

The functions in this module, fips186_prime_gen() and key_gen(), partially follow those specifications, but they do not enforce the minimum strength specifications (2048-bit moduli). I want to be able to generate some extremely weak keys for demonstration purposes.

Warning

Faithfully following (which we don’t here) secure algorithms does not mean that an implementation is secure. These are not.

Examples#

So that documentation building doesn’t take too long, we will use a tiny key size.

# Do not use RSA keys smaller than 2048 bits,
# Do as I say, not as I do
pub_key, priv_key = rsa.key_gen(strength=56, key_size=512)
assert pub_key.N.bit_length() == 512

Now we set up a message to encrypt with the tiny key. Any integer we encryption with a 512 bit key must be less than \(2^{512}\). OAEP padding (with SHA1) would take up 322 bits, so we will just use primitive RSA.

message = int.from_bytes(b"Attack @ dusk!")
assert message.bit_count() < 512

ctext = pub_key.encrypt(message)
decrypted = priv_key.decrypt(ctext)
assert message == decrypted

The API#

toy_crypto.rsa.fips186_prime_gen(n_len: int, e: int = 65537, k: int = 4) tuple[int, int][source]#

Prime generation from Appendix A.1.3 of FIPS 186-5v2

Parameters:
  • n_len (int) – Desired length of modulus in bits

  • e (int, default: 65537) – Public exponent.

  • k (int, default: 4) – Trials for primality testing.

Raises:
  • ValueError – if e is out of range or odd.

  • Exception – if it fails to find suitable primes after trying really hard.

Return type:

tuple[int, int]

toy_crypto.rsa.key_gen(strength: int = 112, key_size: int = 2048, e: int = 65537) tuple[PublicKey, PrivateKey][source]#

Generates private key.

Parameters:
  • strength (int, default: 112) – Intended security parameter (in bits).

  • key_size (int, default: 2048) – size in bits of desired modulus.

  • e (int, default: 65537) – public exponent.

Raises:
  • ValueError – if bit_size is even smaller that the small values allowed by this toy.

  • ValueError – if bit_size doesn’t correspond to an even number of bytes. (This is not a requirement of standards, but is of this implementation.)

  • ValueError – if e is out of range or is not odd.

  • ValueError – if key_size doesn’t provide target strength.

  • Exception – if key that would be generated doesn’t seem to work.

  • Exception – if prime generation fails.

Return type:

tuple[PublicKey, PrivateKey]

Warning

This allows for the generation of unconscionably small keys. But that is ok, because this is a toy implementation in lots of other respects, too.

Partially follows NIST SP 80056B, §6.3.1.

toy_crypto.rsa.estimate_strength(key_size: int) int[source]#

Strength estimate for key size.

From NIST SP-800-56B r2 Appendix D.

Parameters:

key_size (int) – Modulus size in bits

Return type:

int