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.
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
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)
I am creating a program that encrypts and decrypt data. I need to calculate the secret key but I can't work out how to change the algebra into a expression that can be used in python.
I tried using algebra but I could not figure it out.
I'm using python 3.6.1
def genkey():
p = 3 #prime 1
q = 11 #prime 2
n = p * q# pubkey part 1
z = (p-1)*(q-1)# 20
k = 7 #coprime to z and pub key part 2
#j = ?
return (n,k,j)
j should equal 3 and formula is
k * j = 1 ( mod z )
I am using pre-calculated numbers for testing
Link to site
For RSA:
I will provide some algorithms and codes from my own Bachelor Thesis
p and q, two prime numbers
n = p*q, n is the part of the public key
e or public exponent should be coprime with Euler function for n which is (p-1)(q-1) for prime numbers
Code for finding public exponent:
def find_public_key_exponent(euler_function):
"""
find_public_key_exponent(euler_function)
Finds public key exponent needed for encrypting.
Needs specific number in order to work properly.
:param euler_function: the result of euler function for two primes.
:return: public key exponent, the element of public key.
"""
e = 3
while e <= 65537:
a = euler_function
b = e
while b:
a, b = b, a % b
if a == 1:
return e
else:
e += 2
raise Exception("Cant find e!")
next we need modular multiplicative inverse of Euler function(n) and e, which equals d, our last component:
def extended_euclidean_algorithm(a, b):
"""
extended_euclidean_algorithm(a, b)
The result is the largest common divisor for a and b.
:param a: integer number
:param b: integer number
:return: the largest common divisor for a and b
"""
if a == 0:
return b, 0, 1
else:
g, y, x = extended_euclidean_algorithm(b % a, a)
return g, x - (b // a) * y, y
def modular_inverse(e, t):
"""
modular_inverse(e, t)
Counts modular multiplicative inverse for e and t.
:param e: in this case e is a public key exponent
:param t: and t is an Euler function
:return: the result of modular multiplicative inverse for e and t
"""
g, x, y = extended_euclidean_algorithm(e, t)
if g != 1:
raise Exception('Modular inverse does not exist')
else:
return x % t
Public key: (n, e)
Private key: (n, d)
Encryption: <number> * e mod n = <cryptogram>
Decryption: <cryptogram> * d mon n = <number>
There are some more restrictions so the cipher should be secure but it will work with conditions I provided.
And of course you need to find your way to get large prime numbers, read about prime testing
I created a small code for testing RSA, but when I try to decrypt a message
with keys that are 6-7 digit long, it takes a while and gives me the wrong
result.
from math import sqrt
def isPrime(n):
x = int(sqrt(n)) + 1
if n < 2:
return False`
for i in range(2, x):
if (n / i).is_integer():
return (i, False
return True
def factor(num):
hold = list()
inum = int(sqrt(num) + 1)
hold.append((1, num))
if num % 2 == 0: hold.append((2, int(num / 2)))
for i in range(3, inum, 2):
x = num / i
if x.is_integer():
hold.append((i, int(x)))
return hold
def egcd(a, b):
#Extended Euclidean Algorithm
x,y, u,v = 0,1, 1,0
while a != 0:
q, r = b//a, b%a
m, n = x-u*q, y-v*q
b,a, x,y, u,v = a,r, u,v, m,n
gcd = b
return y
def fastMod(n, e):
if e == 0:
return 1
if e % 2 == 1:
return n * fastMod(n, e - 1)
p = fastMod(n, e / 2)
return p * p
def decrypt(p, q, em):
#Uses CRT for decrypting
mp = em % p; mq = em % q;
dp = d % (p-1); dq = d % (q-1);
xp = fastMod(mp, dp) % p; xq = fastMod(mq, dq) % q
log = egcd(p, q)
cp = (p-log) if log > 0 else (p+log)
cq = cp
m = (((q*cp)*xp) + ((p*cq)*xq)) % n
return m
def encrypt(pm):
return fastMod(pm, e) % n
Is there any way to improve speed or fix any errors?
I try to decrypt a few messages I made with a key 9-10 digits long, but it takes
too long.
A lot of things need improvement, but most notably:
For RSA encryption/decryption: fastMod( ) should take the modulus as an input parameter, and reduce by the modulus each iteration. I found this code which illustrates the right way to do it.
For parameter generation: In practice, one could never use a function like your isPrime( ) to determine primality because it runs in exponential time. Instead, you should be doing Miller-Rabin / Strong pseudo prime tests, which can use fastMod( ) as a sub-routine.
By the way, you are implementing textbook RSA here, which is hugely insecure. You would need to use padding such as OAEP to have security, but you need to be very careful on how you implement that to prevent various forms of attacks (such as side channel attacks).
As for why you are getting the wrong result, it is hard to tell without seeing all of your code. Maybe you want to include a main function that generates params and tries to use them for encryption and decryption.
EDIT: I did notice this which looks suspicious: log = egcd(p, q). Not sure what you are doing here. I suggest you first compute d as the inverse of e mod (p-1)*(q-1) and verify that you are getting that correct (ie multiply d*e mod (p-1)*(q-1) and make sure the result is 1). If so, then do a fastMod( ) with d to see if it decrypts (it should). Once you get that working, then move on to making CRT work.
I'm working on a Python project which is supposed to encrypt, send and then decrypt messages with RSA. (I precise it's not a professional project)
I've written a small program to create these keys, and I thought it would work however I think there's a problem in my keys.
The keys are created this way :
def generate_integer ():
i = 0
number = ""
number += str(randrange(1,10))
while i < 1:
number += str(randrange(0,10))
i += 1
return int (number)
def generate_prime_integers ():
p = generate_integer ()
q = 0
premiers = False
while not prime:
q = generate_integer ()
prime = extended_euclide (p, q, False)
if p == q:
prime = False
return p, q
def generate_prime_with_Euler (i_Euler):
prime_with_Euler = False
while not prime_with_Euler:
e = randrange(2,100)
prime_with_Euler = extended_euclide (e, i_Euler, False)
return e
def extended_euclide (a,b,calculate_bezout):
r = a
u = 1
v = 0
r2 = b
u2 = 0
v2 = 1
quotient = 0
while r2 != 0:
q = r // r2
(r, u, v, r2, u2, v2) = (r2, u2, v2, r - q * r2, u - q * u2, v - q * v2)
prime = False
if r == 1:
prime = True
if calculate_bezout:
return u
else:
return prime
def calculate_d (e, i_Euler):
u = extended_euclide (e, i_Euler, True)
return u
def create_keys():
d = -1
while d < 0:
p, q = generate_prime_integers()
n = p*q
i_Euler = (p-1) * (q-1)
e = generate_prime_with_ Euler (i_Euler)
d = calculate_d (e, i_Euler)
return n, e, d
A few explanations : e is the encrypting exponent, d is the decrypting exponent, i_Euler is the Phi(n) function.
The function called is create_keys (), it uses all the functions above to create the 2 keys, public and private. I took the function 'extended_euclide' from Wikipedia, because I had no idea how to code the algorithm of Euclide, and modified it a bit so that it either gives me d (when I give True as third parameter) or tells if the two integers are relatively prime (when giving False).
So, the problem is : when I create my keys and try to encrypt/decrypt any value, it's not working
>>> n,e,d = create_keys()
n : 1634
e : 47
d : 293
>>> message = 64
>>> encrypted_message = pow (message, e, n)
>>> encrypted_message
1208
>>> decrypted_message = pow (encrypted_message, d, n)
>>> decrypted_message
140
Here, decrypted_message should be equal to message, that is to say, 64. Why is it not working ? Is there a problem in the creation of my keys, or is this another issue ?
Edit:
Thanks #BurningKarl I had indeed forgoten to check if p and q were prime numbers. Here's the new function which replaces generate_integer ()
def generate_prime_integer ():
prime= False
while not prime:
number= randrange (10,100)
square_root= int (sqrt (nombre))
if square_root< sqrt (nombre):
square_root+= 1
square_root+= 1
prime= True
for i in range (2, square_root):
if number % i == 0:
prime = False
return number
With that code it seems to be working properly.
Here is my comment as an answer:
When looking at the RSA Wikipedia page it states:
A user of RSA creates and then publishes a public key based on two large prime numbers, along with an auxiliary value.
So for the encryption to work prime numbers are needed while extended_euclide (p, q, False) only checks whether p and q are comprime, i.e. whether their greatest common divisor is 1.
I am trying this problem for a while but getting wrong answer again and again.
number can be very large <=2^2014.
22086. Prime Power Test
Explanation about my algorithm:
For a Given number I am checking if the number can be represented as form of prime power or not.
So the the maximum limit to check for prime power is log n base 2.
Finally problem reduced to finding nth root of a number and if it is prime we have our answer else check for all i till log (n base 2) and exit.
I have used all sort of optimizations and have tested enormous test-cases and for all my algorithm gives correct answer
but Judge says wrong answer.
Spoj have another similar problem with small constraints n<=10^18 for which I already got accepted with Python and C++(Best solver in c++)
Here is My python code Please suggest me if I am doing something wrong I am not very proficient in python so my algorithm is a bit lengthy. Thanks in advance.
My Algorithm:
import math
import sys
import fractions
import random
import decimal
write = sys.stdout.write
def sieve(n):
sqrtn = int(n**0.5)
sieve = [True] * (n+1)
sieve[0] = False
sieve[1] = False
for i in range(2, sqrtn+1):
if sieve[i]:
m = n//i - i
sieve[i*i:n+1:i] = [False] * (m+1)
return sieve
def gcd(a, b):
while b:
a, b = b, a%b
return a
def mr_pass(a, s, d, n):
a_to_power = pow(a, d, n)
if a_to_power == 1:
return True
for i in range(s-1):
if a_to_power == n - 1:
return True
a_to_power = (a_to_power * a_to_power) % n
return a_to_power == n - 1
isprime=sieve(1000000)
sprime= [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]
def smooth_num(n):
c=0
for a in sprime:
if(n%a==0):
c+=1
if(c>=2):
return True;
return False
def is_prime(n):
if(n<1000000):
return isprime[n]
if any((n % p) == 0 for p in sprime):
return False
if n==2:
return True
d = n - 1
s = 0
while d % 2 == 0:
d >>= 1
s += 1
for repeat in range(10):
a=random.randint(1,n-1)
if not mr_pass(a, s, d, n):
return False
return True
def iroot(n,k):
hi = 1
while pow(hi, k) < n:
hi *= 2
lo = hi // 2
while hi - lo > 1:
mid = (lo + hi) // 2
midToK = (mid**k)
if midToK < n:
lo = mid
elif n < midToK:
hi = mid
else:
return mid
if (hi**k) == n:
return hi
else:
return lo
def isqrt(x):
n = int(x)
if n == 0:
return 0
a, b = divmod(n.bit_length(), 2)
x = pow(2,(a+b))
while True:
y = (x + n//x)>>1
if y >= x:
return x
x = y
maxx=2**1024;minn=2**64
def nth_rootp(n,k):
return int(round(math.exp(math.log(n)/k),0))
def main():
for cs in range(int(input())):
n=int(sys.stdin.readline().strip())
if(smooth_num(n)):
write("Invalid order\n")
continue;
order = 0;m=0
power =int(math.log(n,2))
for i in range(1,power+1):
if(n<=maxx):
if i==1:m=n
elif(i==2):m=isqrt(n)
elif(i==4):m=isqrt(isqrt(n))
elif(i==8):m=isqrt(isqrt(isqrt(n)))
elif(i==16):m=isqrt(isqrt(isqrt(isqrt(n))))
elif(i==32):m=isqrt(isqrt(isqrt(isqrt(isqrt(n)))))
elif(i==64):m=isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(n))))))
elif(i==128):m=isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(n)))))))
elif(i==256):m=isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(n))))))))
else:m=int(nth_rootp(n,i))
else:
if i==1:m=n
elif i==2:m=isqrt(n)
elif(i==4):m=isqrt(isqrt(n))
elif(i==8):m=isqrt(isqrt(isqrt(n)))
elif(i==16):m=isqrt(isqrt(isqrt(isqrt(n))))
elif(i==32):m=isqrt(isqrt(isqrt(isqrt(isqrt(n)))))
elif(i==64):m=isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(n))))))
elif(i==128):m=isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(n)))))))
elif(i==256):m=isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(isqrt(n))))))))
else:m=iroot(n,i)
if m<2:
order=0
break
if(is_prime(m) and n==(m**i)):
write("%d %d\n"%(m,i))
order = 1
break
if(order==0):
write("Invalid order\n")
main()
I'm not going to read all that code, though I suspect the problem is floating-point inaccuracy. Here is my program to determine if a number n is a prime power; it returns the prime p and the power k:
# prime power predicate
from random import randint
from fractions import gcd
def findWitness(n, k=5): # miller-rabin
s, d = 0, n-1
while d % 2 == 0:
s, d = s+1, d/2
for i in range(k):
a = randint(2, n-1)
x = pow(a, d, n)
if x == 1 or x == n-1: continue
for r in range(1, s):
x = (x * x) % n
if x == 1: return a
if x == n-1: break
else: return a
return 0
# returns p,k such that n=p**k, or 0,0
# assumes n is an integer greater than 1
def primePower(n):
def checkP(n, p):
k = 0
while n > 1 and n % p == 0:
n, k = n / p, k + 1
if n == 1: return p, k
else: return 0, 0
if n % 2 == 0: return checkP(n, 2)
q = n
while True:
a = findWitness(q)
if a == 0: return checkP(n, q)
d = gcd(pow(a,q,n)-a, q)
if d == 1 or d == q: return 0, 0
q = d
The program uses Fermat's Little Theorem and exploits the witness a to the compositeness of n that is found by the Miller-Rabin algorithm. It is given as Algorithm 1.7.5 in Henri Cohen's book A Course in Computational Algebraic Number Theory. You can see the program in action at http://ideone.com/cNzQYr.
this is not really an answer, but I don't have enough space to write it as a comment.
So, if the problem still not solved, you may try the following function for nth_rootp, though it is a bit ugly (it is just a binary search to find the precise value of the function):
def nth_rootp(n,k):
r = int(round(math.log(n,2)/k))
left = 2**(r-1)
right = 2**(r+1)
if left**k == n:
return left
if right**k == n:
return right
while left**k < n and right**k > n:
tmp = (left + right)/2
if tmp**k == n:
return tmp
if tmp == left or tmp == right:
return tmp
if tmp**k < n:
left = tmp
else:
if tmp**k > n:
right = tmp
your code look like a little overcomplicated for this task, I will not bother to check it, but the thing you need are the following
is_prime, naturally
a prime generator, optional
calculate the nth root of a number in a precise way
for the first one I recommend the deterministic form of the Miller-Rabin test with a appropriate set of witness to guaranty a exact result until 1543267864443420616877677640751301 (1.543 x 1033) for even bigger numbers you can use the probabilistic one or use a bigger list of witness chosen at your criteria
with all that a template for the solution is as follow
import math
def is_prime(n):
...
def sieve(n):
"list of all primes p such that p<n"
...
def inthroot(x,n):
"calculate floor(x**(1/n))"
...
def is_a_power(n):
"return (a,b) if n=a**b otherwise throw ValueError"
for b in sieve( math.log2(n) +1 ):
a = inthroot(n,b)
if a**b == n:
return a,b
raise ValueError("is not a power")
def smooth_factorization(n):
"return (p,e) where p is prime and n = p**e if such value exists, otherwise throw ValueError"
e=1
p=n
while True:
try:
p,n = is_a_power(p)
e = e*n
except ValueError:
break
if is_prime(p):
return p,e
raise ValueError
def main():
for test in range( int(input()) ):
try:
p,e = smooth_factorization( int(input()) )
print(p,e)
except ValueError:
print("Invalid order")
main()
And the code above should be self explanatory
Filling the blacks
As you are familiar with Miller-Rabin test, I will only mention that if you are interested you can find a implementation of the determinist version here just update the list of witness and you are ready to go.
For the sieve, just change the one you are using to return a list with primes number like this for instance [ p for p,is_p in enumerate(sieve) if is_p ]
With those out of the way, the only thing left is calculate the nth root of the number and to do that in a precise way we need to get rip of that pesky floating point arithmetic that only produce headaches, and the answer is implement the Nth root algorithm using only integer arithmetic, which is pretty similar to the one of isqrt that you already use, I guide myself with the one made by Mark Dickinson for cube root and generalize it and I get this
def inthroot(A, n) :
"calculate floor( A**(1/n) )"
#https://en.wikipedia.org/wiki/Nth_root_algorithm
#https://en.wikipedia.org/wiki/Nth_root#nth_root_algorithm
#https://stackoverflow.com/questions/35254566/wrong-answer-in-spoj-cubert/35276426#35276426
#https://stackoverflow.com/questions/39560902/imprecise-results-of-logarithm-and-power-functions-in-python/39561633#39561633
if A<0:
if n%2 == 0:
raise ValueError
return - inthroot(-A,n)
if A==0:
return 0
n1 = n-1
if A.bit_length() < 1024: # float(n) safe from overflow
xk = int( round( pow(A,1.0/n) ) )
xk = ( n1*xk + A//pow(xk,n1) )//n # Ensure xk >= floor(nthroot(A)).
else:
xk = 1 << -(-A.bit_length()//n) # 1 << sum(divmod(A.bit_length(),n))
# power of 2 closer but greater than the nth root of A
while True:
sig = A // pow(xk,n1)
if xk <= sig:
return xk
xk = ( n1*xk + sig )//n
and with all the above you can solve the problem without inconvenient
from sympy.ntheory import factorint
q=int(input("Give me the number q="))
fact=factorint(q) #We factor the number q=p_1^{n_1}*p_2^{n_2}*...
p_1=list(fact.keys()) #We create a list from keys to be the the numbers p_1,p_2,...
n_1=list(fact.values()) #We create a list from values to be the the numbers n_1,n_2,...
p=int(p_1[0])
n=int(n_1[0])
if q!=p**n: #Check if the number q=p_{1}[0]**n_{1}[0]=p**n.
print("The number "+str(q)+" is not a prime power")
else:
print("The number "+str(q)+" is a prime power")
print("The prime number p="+str(p))
print("The natural number n="+str(n))