Python RSA Brute Force Check - python

I have an exercise to brute force a piece of text that has been encrypted with a very small key. The public key I have is (e = 5, n = 203). The text has been converted to ASCII, shifted a fixed number and then encrypted with the RSA public key. I have to decrypt this text using brute force only. To decrypt I'm using the simple formula of:
decrypt = (value**d)%n
Where value is the thing I want to decrypt, d being the value I am unsure of and n being the modulus.
So far I have put the numbers in a tuple called en and I loop through it like this:
for i in range(1,10):
for a in range(0,41):
ans = (en[a]**i)%203
print (chr(ans))
The first for loop is "d" the private key value I am not sure of and the second for loop is for going through the 41 length tuple. I don't have the block shift part implemented yet but I want to check if this is the correct way of brute forcing a simple RSA key.

You should try to factor n by brute force:
for i in range(n):
if n%i == 0:
print i
, from which you will find p=7 and q=29.
d = e^-1 mod phi(n)
= e^-1 mod (p-1)*(q-1)
therefore d = e^-1 mod 168, ergo d=162.

I took the liberty to improve on L3viathan's answer and provide a full working source ready to copy paste and run:
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def factor(n):
for i in range(3, n):
if n%i == 0:
return i
e = 5
n = 203
p = factor(n)
q = n//p
phi_n = (p-1) * (q-1)
# Only for python >= 3.8
# From https://docs.python.org/3/library/functions.html#pow
# If mod is present and exp is negative, base must be relatively prime to mod.
# In that case, pow(inv_base, -exp, mod) is returned, where inv_base is an inverse to base modulo mod.
# d_crack = pow(e, -1, phi_n)
# python < 3.8
d_crack = modinv(e, phi_n)
print('cracked d:', d_crack) # prints "cracked d: 101"

Related

RSA Cryptography shows wrong result for large prime numbers

I implemented a RSA Cryptography program, using python, and it works perfectly using prime numbers with aproximally 10 digits. But when I use numbers with 25 digits or more, for example, it does not work.
It worked with the following keys:
p = 2324731
q = 186647
e = 433899328297
n = 433904066957
It not worked with:
p = 3673864730662357928718503
q = 2127738717256957618781057
e = 7817024229395103552360986476332293342120062315901
n = 7817024229395103552360993847944520620136941797671
here's the code:
inverse (d key):
#classmethod
def __linearOperation(cls, a, b, mdc, i):
t = -int(a / b)
r = a % b
mdc.append([1, a, t, b])
if r == 1:
return mdc
inverseLine = cls.__linearOperation(b, r, mdc, i + 1)
s = inverseLine[i][0]
t = inverseLine[i][2]
inverseLine[i - 1][0] *= t
inverseLine[i - 1][2] *= t
inverseLine[i - 1][2] += s
inverseLine.remove(inverseLine[i])
return inverseLine
def __inverse(self, e, φ):
inverseLine = self.__linearOperation(e, φ, [], 1)
inverse = inverseLine[0][0]
if inverse < 0:
return inverse + φ
if inverse > φ:
return inverse % φ
else:
return inverse
Modular Exponentiation:
#staticmethod
def __QuickMod(base, exp, n):
result = 1
while exp > 0:
if exp & 1:
result = (result * base) % n
base = (base ** 2) % n
exp = exp >> 1
return result
encrypt/decrypt:
def encryptChar(self, n: int, e: int, M: int) -> int:
C = self.__QuickMod(M, e, n) # C = M^e mod n
return C
def decryptChar(self, p: int, q: int, e: int, C: int) -> int:
d = self.__inverse(e, (p - 1) * (q - 1))
M = self.__QuickMod(C, d, p * q) # M = C^d mod n
return M
By trying to encrypt the number 109 ("m" char in ascII), the encryptChar function returns 6825028446539883496812231478440519650519629664279.
By trying to decrypt the number above the decryptChar function should returns the number 109 back. But that's not what happens.
In my conception, by using python we do not have number size restriction.
Is there something i'm not seeing? Thank you for your help.
The problem is in my inverse algorithm. I'll try to re-implement it. But using pow() function with -1 as expoent works.

how can I handle large numbers in Python?

I would like to make a Python code for Paillier Encryption and I have made the code, which works well with small number e.g. 32bit. But I would like to make it work even though the number is very very large (till 1024 bit)
So I tried this code which p,q (random choosed Primenumber)
here is the code
from random import randint
import libnum
import sys
import random
import numpy as np ## in order to save the time
def gcd(a,b):
"""Compute the greatest common divisor of a and b"""
while b > 0:
a, b = b, a % b
return a
def lcm(a, b):
"""Compute the lowest common multiple of a and b"""
return a * b // gcd(a, b)
def L(x,n):
return ((x-1)//n)
#%% Key generation (Schlüsselerzeugung)
find_primenumber=2**513
# um die
a = [False,False] + [True]*(find_primenumber-1)
primes=[]
# Algorism of eratosthenes
for i in range(2,find_primenumber+1):
if a[i]:
primes.append(i)
for j in range(2*i, find_primenumber+1, i):
a[j] = False
# print('the choosable prime numbers are : ',primes)
p= random.sample(primes, 2)[0]
q=random.sample(primes, 2)[1] ## two prime numbers are randomly choosed
# öffentliche Schlüssel public key (n,g)
n = p*q
# um Schlüssellänge zu vergrößen, muss n noch größer werden
# sys.getsizeof(n)
# in case n = 2499995600000711 size of n is 32
g = n+1 #Pick a random integer g in the set Z∗n2 (integers between 1 and n2)
gLambda = lcm(p-1,q-1) ## in Matlab cipher = lambda
m= str(input('Enter plaintext :')) #must be string type
m= list(m)
m_list=[]
for i in range(0,len(m)):
m_list.append(ord(m[i])) ## must be saved as a list
m_1=np.array(m_list)
if (len(sys.argv)>1):
m=int(sys.argv[1])
if (len(sys.argv)>2):
p=int(sys.argv[2])
if (len(sys.argv)>3):
q=int(sys.argv[3])
if (p==q):
print("P and Q cannot be the same")
sys.exit()
l = (pow(g, gLambda, n*n)-1)//n
gMu = libnum.invmod(l, n)
if (gcd(g,n*n)==1):
print("g is relatively prime to n*n")
else:
print("WARNING: g is NOT relatively prime to n*n. Will not work!!!")
# geheime Schlüssel (private key)
r=[]
for i in range(0,len(m)):
r.append(randint(1,n))
#%% Encryption
# changed: pow(a,b,n) for modular exponentiation a^b mod n
# --> much faster than the standard pow()
# shortened the code
c=[]
for i in range(0,len(m)):
k1 = pow(g, m_list[i], n**2)
k2 = pow(r[i], n, n**2)
c.append((k1*k2)%(n**2));
but I get this answer from the Console
OverflowError: cannot fit 'int' into an index-sized integer
How can I fix it and make it work even the find_primenumber is large enough?

Why the program does not correctly search for the general solution of the Diophantine equation

I wrote a program that looks for a general solution to a Diophantine equation, but the solution is not entirely correct when I check the online calculator. For example, for the equation "45x-128y=177" the solution in general form should be "x=6549-128k" and "y=2301-45k", but I get "x=6549+k128" and
"y=-2301+k45".
My code:
import re
def extended_gcd(a, b):
if a == 0:
return (0, 1)
(x, y) = extended_gcd(b % a, a)
return (y - (b // a) * x), x
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def main():
s = input('Enter the Diophantine equation: ')
s1 = re.findall(r'\d+', s)
a = int(s1[0])
b = int(s1[1])
c = int(s1[2])
d = gcd(a, b)
print(f'GCD({a},{b}) = {d}')
if d % c != 0:
print('This equation has an infinite set of solutions')
a1 = a // d
b1 = b // d
print(f'Short equation: {a1}s + {b1}t = {1}')
(s, t) = extended_gcd(a1, b1)
x0 = (c // d) * s
y0 = (c // d) * t
print("General solution")
print(f"x = {x0} + k * {b // d}")
print(f"y = {y0} + k * {a // d}")
else:
print('This equation has no solution')
if __name__ == "__main__":
main()
What is the problem and how to solve it?
One Python problem you have is your regex does not match negative numbers, ie in your example s1[1] is 128 not -128. To match the sign you can change the regex matching line to
s1 = re.findall(r'[-+]?\d+', s)
so s1[1] is now the correct -128, as you can check by printing it at the right point
It still does not produce the right answer it seems but at least the inputs should be correct after the fix. You should double check that you coded the algorithm correctly and for example print intermediate results and check them against your by-hand (or Excel) calculations. We can help you with coding problems here but not so much with your algorithm issues...

Python - RSA decryption does not return original message (very simple, short program)

So I am trying to create a very simple RSA encryption/decryption program where I only encrypt/decrypt int numbers. All works fine except for one problem. Sometimes my decrypted number (message) does not match my original number (the message I needed to encrypt and decrypt). This seems to happen whenever my inputted number (message) is close to my the number in my 'n' variable (n=p*q where p and q are prime numbers). I have browsed Stackoverflow a bit now and have found out that RSA algoritms cannot properly decrypt messages that are greater than 'n'. But in my case it fails to decrypt messages that are close to 'n'. If n=35 and my input number (the number to encrypt/decrypt) is 32, the program does not properly decrypt it back to 32 despite 32 being lower than 35 (works for 31, 30 ... though). Why?
Code:
import math
def isPrime(n):
if n>=2:
for m in range(2, int(math.sqrt(n)+1)):
if n%m == 0:
return False
return True
else:
return False
def gcd(x, y):
while y != 0:
(x, y) = (y, x % y)
return x
def phi(n):
amount = 0
for k in range(1, n + 1):
if gcd(n, k) == 1:
amount += 1
return amount
def findPubE(n, phiN):
for e in range(3, n, 2):
if gcd(e,phiN)==1:
return e
else:
raise AssertionError("cannot find 'e'")
def multiplicative_inverse(a, b):
"""Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb
"""
# r = gcd(a,b) i = multiplicitive inverse of a mod b
# or j = multiplicitive inverse of b mod a
# Neg return values for i or j are made positive mod b or a respectively
# Iterateive Version is faster and uses much less stack space
x = 0
y = 1
lx = 1
ly = 0
oa = a # Remember original a/b to remove
ob = b # negative values from return results
while b != 0:
q = a // b
(a, b) = (b, a % b)
(x, lx) = ((lx - (q * x)), x)
(y, ly) = ((ly - (q * y)), y)
if lx < 0:
lx += ob # If neg wrap modulo orignal b
if ly < 0:
ly += oa # If neg wrap modulo orignal a
# return a , lx, ly # Return only positive values
return lx
def encrypt(m,e,n):
return (m^(e)) % n
def decrypt(M, d):
return M^(d)
def main():
p=int(input("Input first prime number (p): "))
q=int(input("Input second prime number (q): "))
n=p*q
print("n = ",n)
msg= int(input("Input message: "))
assert msg < n
phiN=(p-1)*(q-1)
e = findPubE(n,phiN)
d = multiplicative_inverse(e,phiN)
encryptedMsg = encrypt(msg,e,n)
decryptedMsg = decrypt(encryptedMsg,d)
assert isPrime(p) and isPrime(q)
print("phi(n) = ",phiN)
print("e = ",e)
print("d = ",d)
print("Encrypted message: ",encryptedMsg)
print("Decrypted message: ",decryptedMsg)
main()
Solved it! I made two little mistakes in my code. First one was that I assumed that the "^" symbol meant "to the power of" in Python (the correct symbol is "**") and the second one was that I forgot to add "mod n" to the line in my decrypt() function (so return M**(d) % n instead of return M^(d)).

None value in python numerical integration function

I'm trying to write a code that calculates integrals using the rectangular rule and also allows the user to input the integral limits and number of divions(rectangles). I've written the function, but for certain values it just returns "None". Any idea why?
Here's my code so far:
def integral(f, a, b, N):
h = int((b-a)/N)
result = 0
result += h * f(a)
for i in range(1, N-1):
result += h * f(a + i*h)
return result
def f(x):
return x**3
string_input1 = input("Please enter value for a: ")
a = int(string_input1)
string_input2 = input("Please enter value for b: ")
b = int(string_input2)
while True:
string_input3 = input("Please enter integer positive value for N: ")
N = int(string_input3)
if N>0:
break
print(integral(f, a, b, N))
an example of values that return "None" is a=0 b=1 N=2
for i in range(1, N-1):
result += h * f(a + i*h)
return result
If N = 2 then for i in range(1, 1) is not going to execute, thus integral returns None.
But even if N > 2, having return inside the for loop doesn't make any sense since it will only run the first iteration and then return whatever result is.
The first problem was the variable h as an int, then the loop until N-1 and after that the return inside the loop.
def integral(f,a,b,N):
h = float(b-a)/float(N)
result = 0.
result += h*f(a)
for i in range(1,N):
result += h*f(a+i*h)
return result
You already have a good answer, but your code could be refined a bit:
There is no reason to treat the leftmost endpoint any differently that the other sample points. Since a = a + 0, if you start the loop with i=0, you pick up a in the first pass through the loop:
def integral(f,a,b,N):
h = (b-a)/float(N)
result = 0.0
for i in range(N):
result += h*f(a+i*h)
return result
Furthermore, it would be more Pythonic to replace the explicit loop by directly applying sum to a comprehension:
def integral(f,a,b,N):
h = (b-a)/float(N)
return h*sum(f(a + i*h) for i in range(N))
This is functionally the same as the first definition. For example:
>>> integral(lambda x: x**2,0,1,100)
0.32835000000000003
Finally, if you are using Python 2, the above should be changed so that it uses xrange() rather than range().

Categories

Resources