-1

I'm writing a program that will calulate the private key for a weak RSA public key. I am wondering how I would go about determining the values for p and q from the value n. Here is the Python code so far:

from Crypto.PublicKey import RSA #PyCryptoDome
import .math as cm # My own module

with open(public_keyfile, 'rb') as key: # Public Keyfile Is in PEM format
    public_key = RSA.import_key(key)

n = public_key.n # N value of the public_key

e = public_key.e # E value of the public_key

p, q = get_factors_of(n) # This I don't know how to do, though there is a question that might help [see bottom]

t = cm.lcm(p-1, q-1) # Get the lowest common multiple of q and q

d = cm.mod_inverse(e, t) # Get d, the modular inverse of e % t

private_key = RSA.construct((n, e, d, p, q) # Construct the RSA private_key

The .math module referenced above:

from math import gcd


def mod_inverse(a, b):
    a = a % b
    for x in range(1, b):
        if (a * x) % b == 1:
            return x
    return 1


def lcm(x, y):
    return x * y // gcd(x, y)

What I need to do appears to be referenced here but this code is in Java.

If anyone knows how to get p and q from n with python, help would be appreciated.

Many thanks, Legorooj.

Legorooj
  • 2,646
  • 2
  • 15
  • 35
  • 4
    SO is not a free code conversion service. Do the conversion to Python, then post your code with questions. – lit Jun 06 '19 at 09:54
  • I know. I don't understand Java whatsoever, I was hoping that SO would be able to to help with how to get `p` and `q` from `n` with python. – Legorooj Jun 06 '19 at 09:57
  • 2
    Do you understand how to do it manually? If not, then you really have a math question, not a programming question (and especially not a Python question). If you do, then start there and ask a more specific question if you can't get the implementation working. – Karl Knechtel Jun 06 '19 at 09:59
  • I don't think you have an understanding of the difficulty of factoring large integers that are products of two approximately equal primes, i.e. RSA moduli. Without lots of hardware and/or time you won't be able to do it. – President James K. Polk Jun 06 '19 at 14:43
  • Fortunately I have both. @KarlKnechtel, I understand how to do it manually, and have found a way to implement it - as pseudocode only at the moment. If it works, i shall answer my own question. If not, I shall ask a new question about why the implentation doesn't work. – Legorooj Jun 06 '19 at 18:45

2 Answers2

3

Mandatory warning: if you are after performance, you will need to investigate the details of the algorithms yourself. Even "weak" public keys will take forever to crack with a simplistic algorithm (e.g. Erathostene's sieve).

That being said, sympy.ntheory.factorint() might be what you need:

from sympy.ntheory import factorint

print(factorint(54))  # {2: 1, 3: 3} i.e. 54 == 2**1 * 3**3
Leporello
  • 638
  • 4
  • 12
  • Thanks for this answer, but `smpy.ntheory.factorint()` takes way too long with this test integer: `9236378997685682877721661094972497924039685752827371833327322710323377895840902638303442492100881746878186386244383135186587004052271180780932725919664899` – Legorooj Jun 06 '19 at 11:15
  • `math.log(your number, 2)` returns ~512. Again, even a "weak" public key will take forever to crack. The Wikipedia page https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Integer_factorization_and_RSA_problem makes me think RSA-512 is still a tough nut to crack for one random guy using Python, even if unsafe to use (because attackers are number theorists with access to decent hardware). – Leporello Jun 06 '19 at 11:22
  • It also begs the question of what you are using your program for, since I bet there are some businesses around that still use RSA-512... – Leporello Jun 06 '19 at 11:25
  • I'm going to use my program to attack a cipher recipe I came up with - one not disimilar to pgp – Legorooj Jun 06 '19 at 11:48
2

After lots of googling, and pdf reading, I found an algorithm that works. Here is a python implementation:

import math
def get_factors_of(num):
    poss_p = math.floor(math.sqrt(num)) 

    if poss_p % 2 == 0: # Only checks odd numbers, it reduces time by orders of magnitude
        poss_p += 1
    while poss_p < num:
        if num % poss_p == 0:
            return poss_p
        poss_p += 2

This algorithm effectively finds the P/Q factors of a small RSA key. (I have tested it against a 64-bit PEM public key)

Legorooj
  • 2,646
  • 2
  • 15
  • 35