How to encrypt and decrypt message RSA in python? - python

I am trying to write RSA encryption and decryption in python without Crypto library and in short I have generated public(e,N) and private(d,N) keys to exchange with message and I don't know how to that.The message I want to send is also key:b'gAAAAABenIFsZD5Oa7GPNKPV7yBHSKasuzpMzYPPoXbEqX3cbxO_9-3eP9UdKOXsrQmLSesKkaeKk9VZXI6Qx-iWS8tglsxbRwjgdAWPZKQa8NLyH1ICKJgEihrc-9ybO6WgV_jASgHH0zg4mdEP8XhxQmg6-S96HA=='
Does someone know how to encrypt message with my public key and decrypt it with private ?
import random
def gcd(a, b): # gdc to find proper e
if (b == 0):
return a
else:
return gcd(b, a % b)
def isPrime(num):
if num > 1:
for i in range(2, num):
if (num % i) == 0:
return False;
break
else:
return True
else:
return False;
def pGenerator():
p = 0
while p == 0:
pn = random.randint(0, 40)
if (isPrime(pn)):
p = pn
break
return p
def qGenerator(p):
q = 0
while q == 0:
pn = random.randint(0, 40)
if (isPrime(pn) and pn != p and pn <p):
q = pn
break
return q
def eGenerator( fiN):
e = 0
while e == 0:
pn = random.randint(0, fiN)
if (gcd(pn, fiN) == 1):
e = pn
break
return e
def start():
p = pGenerator()
print(p)
q = qGenerator(p)
print(q)
N = p * q
fiN = (p - 1) * (q - 1)
print(fiN)
e = eGenerator(fiN)
d=multiplicative_inverse(e,fiN)
c=encrypt(e, N, "d")
decrypt(d,N,c)
print(c)
def encrypt(e,n, plaintext):
#Unpack the key into it's components
key=e
#Convert each letter in the plaintext to numbers based on the character using a^b mod m
cipher = [(ord(char) ** key) % n for char in plaintext]
#Return the array of bytes
return cipher
def multiplicative_inverse(e, phi):
d = 0
x1 = 0
x2 = 1
y1 = 1
temp_phi = phi
while e > 0:
temp1 = temp_phi / e
temp2 = temp_phi - temp1 * e
temp_phi = e
e = temp2
x = x2 - temp1 * x1
y = d - temp1 * y1
x2 = x1
x1 = x
d = y1
y1 = y
if temp_phi == 1:
return d + phi
start()

Have you tried rsapy?
Just read its docs on its PyPI page.
Example:
import rsapy
pub, pri = rsapy.genkey(2**512)
print(rsapy.encode("message", pub))
# This also works with b"message"

Related

Python Hw, bisection Method

Part A - Bisection Method
Write a function called bisection(n, p) that asks the user to enter a mathematical function f(x)
and two boundary points in order to solve for r such that f(r) = 0 using bisection method.
The function terminates when the solution r is found or when the maximum number of iterations
n is reached (default n = 100), whichever occurs first.
def bisection(n = 100, p = 0.0001):
# code goes below
fx = input("f(x) = ")
a = float(input("Boundary A: "))
x = a
fa = eval(fx)
b = float(input("Boundary B: "))
x = b
fb = eval(fx)
i = 0
if (fa * fb >= 0):
print("Bisection method fails")
return
while(i < n):
m = a + b / 2
x = m
fm = eval(fx)
if(fm * fa < 0):
a = a
b = m
if (fm * fb < 0):
a = m
b = b
i = i + 1
if (fm == 0):
return m
pass
When I input: f(x) = x - 1
Boundary A: 0
Boundary B: 3
No answer is printed so I'm very confused?!
There are lots of problems with this code. For some reason you defined p and never passed it again, I assume it stands for epsilon. You defined midpoint as
a+b/2
which is equivalent to
a+(b/2)
but you need
(a+b)/2
.
Statement
if (fm == 0):
this statement would probably never run because it is hard to get that close to a root for a few iterations.
Instead, use
if (abs(fm<p)):
Modified code
def bisection(n = 250, p = 10**-6):
# code goes below
fx = input("f(x) = ")
a = float(input("Boundary A: "))
x = a
fa = eval(fx)
b = float(input("Boundary B: "))
x = b
fb = eval(fx)
for i in range(1, n+1):
m = (a + b)/2
x = m
fm = eval(fx)
if(fm * fa < 0):
a = a
b = m
elif (fm * fa > 0):
a = m
b = b
elif (abs(fm<p)):
return m
print(bisection())
Output:
f(x) = x - 1
Boundary A: 0
Boundary B: 3
1.0

Is this function i wrote to find prime numbers efficient [duplicate]

This question already has answers here:
Big O, how do you calculate/approximate it?
(24 answers)
Closed 2 years ago.
def is_prime(x):
'''
Function to check if a number is prime
'''
if x == 2:
return True
if x%2 != 0: #Check if number is even since all primes are odd except 2
a = [x % i for i in range(2,x+1)]
b = [i for i in a if i == 0] # Checks to make sure there's only one modulus of 0
if len(b) == 1:
return True
else:
return False
else:
return False
So like yeah please what is the time complexity (all those 0/n things) and how do i find that, a good resource link would be helpful (:
Your complexity is O(x) as you run one loop from 2 to x+1.
You can just check upto sqrt(x). That will bring down the complexity to O(sqrt(x)). (You can break once you find one factor, even though it won't bring down the worst time complexity)
Just change this line -
a = [x % i for i in range(2,math.sqrt(x+1))]
Why up to square root?
You can just google, there are many proofs. The simple one being, if
a = b.c, then the at least there is one divisor of a which is less than sqrt(a), or equal if a is square number a = b*b.
There are many fast heuristic and probabilistic (Miller-Rabin is very famous and frequently used) algorithms for faster prime detection.
Here's one which is deterministic:
The Adleman–Pomerance–Rumely primality test is an algorithm for determining whether a number is prime. Unlike other, more efficient algorithms for this purpose, it avoids the use of random numbers, so it is a deterministic primality test.
It's complexity is log(x)^O(logloglogx)
import copy
import time
from math import gcd # version >= 3.5
# primality test by trial division
def isprime_slow(n):
if n<2:
return False
elif n==2 or n==3:
return True
elif n%2==0:
return False
else:
i = 3
while i*i <= n:
if n%i == 0:
return False
i+=2
return True
# v_q(t): how many time is t divided by q
def v(q, t):
ans = 0
while(t % q == 0):
ans +=1
t//= q
return ans
def prime_factorize(n):
ret = []
p=2
while p*p <= n:
if n%p==0:
num = 0
while n%p==0:
num+=1
n//= p
ret.append((p,num))
p+= 1
if n!=1:
ret.append((n,1))
return ret
# calculate e(t)
def e(t):
s = 1
q_list = []
for q in range(2, t+2):
if t % (q-1) == 0 and isprime_slow(q):
s *= q ** (1+v(q,t))
q_list.append(q)
return 2*s, q_list
# Jacobi sum
class JacobiSum(object):
def __init__(self, p, k, q):
self.p = p
self.k = k
self.q = q
self.m = (p-1)*p**(k-1)
self.pk = p**k
self.coef = [0]*self.m
# 1
def one(self):
self.coef[0] = 1
for i in range(1,self.m):
self.coef[i] = 0
return self
# product of JacobiSum
# jac : JacobiSum
def mul(self, jac):
m = self.m
pk = self.pk
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(m):
for j in range(m):
if (i+j)% pk < m:
j_ret.coef[(i+j)% pk] += self.coef[i] * jac.coef[j]
else:
r = (i+j) % pk - self.p ** (self.k-1)
while r>=0:
j_ret.coef[r] -= self.coef[i] * jac.coef[j]
r-= self.p ** (self.k-1)
return j_ret
def __mul__(self, right):
if type(right) is int:
# product with integer
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(self.m):
j_ret.coef[i] = self.coef[i] * right
return j_ret
else:
# product with JacobiSum
return self.mul(right)
# power of JacobiSum(x-th power mod n)
def modpow(self, x, n):
j_ret=JacobiSum(self.p, self.k, self.q)
j_ret.coef[0]=1
j_a = copy.deepcopy(self)
while x>0:
if x%2==1:
j_ret = (j_ret * j_a).mod(n)
j_a = j_a*j_a
j_a.mod(n)
x //= 2
return j_ret
# applying "mod n" to coefficient of self
def mod(self, n):
for i in range(self.m):
self.coef[i] %= n
return self
# operate sigma_x
# verification for sigma_inv
def sigma(self, x):
m = self.m
pk = self.pk
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(m):
if (i*x) % pk < m:
j_ret.coef[(i*x) % pk] += self.coef[i]
else:
r = (i*x) % pk - self.p ** (self.k-1)
while r>=0:
j_ret.coef[r] -= self.coef[i]
r-= self.p ** (self.k-1)
return j_ret
# operate sigma_x^(-1)
def sigma_inv(self, x):
m = self.m
pk = self.pk
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(pk):
if i<m:
if (i*x)%pk < m:
j_ret.coef[i] += self.coef[(i*x)%pk]
else:
r = i - self.p ** (self.k-1)
while r>=0:
if (i*x)%pk < m:
j_ret.coef[r] -= self.coef[(i*x)%pk]
r-= self.p ** (self.k-1)
return j_ret
# Is self p^k-th root of unity (mod N)
# if so, return h where self is zeta^h
def is_root_of_unity(self, N):
m = self.m
p = self.p
k = self.k
# case of zeta^h (h<m)
one = 0
for i in range(m):
if self.coef[i]==1:
one += 1
h = i
elif self.coef[i] == 0:
continue
elif (self.coef[i] - (-1)) %N != 0:
return False, None
if one == 1:
return True, h
# case of zeta^h (h>=m)
for i in range(m):
if self.coef[i]!=0:
break
r = i % (p**(k-1))
for i in range(m):
if i % (p**(k-1)) == r:
if (self.coef[i] - (-1))%N != 0:
return False, None
else:
if self.coef[i] !=0:
return False, None
return True, (p-1)*p**(k-1)+ r
# find primitive root
def smallest_primitive_root(q):
for r in range(2, q):
s = set({})
m = 1
for i in range(1, q):
m = (m*r) % q
s.add(m)
if len(s) == q-1:
return r
return None # error
# calculate f_q(x)
def calc_f(q):
g = smallest_primitive_root(q)
m = {}
for x in range(1,q-1):
m[pow(g,x,q)] = x
f = {}
for x in range(1,q-1):
f[x] = m[ (1-pow(g,x,q))%q ]
return f
# sum zeta^(a*x+b*f(x))
def calc_J_ab(p, k, q, a, b):
j_ret = JacobiSum(p,k,q)
f = calc_f(q)
for x in range(1,q-1):
pk = p**k
if (a*x+b*f[x]) % pk < j_ret.m:
j_ret.coef[(a*x+b*f[x]) % pk] += 1
else:
r = (a*x+b*f[x]) % pk - p**(k-1)
while r>=0:
j_ret.coef[r] -= 1
r-= p**(k-1)
return j_ret
# calculate J(p,q)(p>=3 or p,q=2,2)
def calc_J(p, k, q):
return calc_J_ab(p, k, q, 1, 1)
# calculate J_3(q)(p=2 and k>=3)
def calc_J3(p, k, q):
j2q = calc_J(p, k, q)
j21 = calc_J_ab(p, k, q, 2, 1)
j_ret = j2q * j21
return j_ret
# calculate J_2(q)(p=2 and k>=3)
def calc_J2(p, k, q):
j31 = calc_J_ab(2, 3, q, 3, 1)
j_conv = JacobiSum(p, k, q)
for i in range(j31.m):
j_conv.coef[i*(p**k)//8] = j31.coef[i]
j_ret = j_conv * j_conv
return j_ret
# in case of p>=3
def APRtest_step4a(p, k, q, N):
print("Step 4a. (p^k, q = {0}^{1}, {2})".format(p,k,q))
J = calc_J(p, k, q)
# initialize s1=1
s1 = JacobiSum(p,k,q).one()
# J^Theta
for x in range(p**k):
if x % p == 0:
continue
t = J.sigma_inv(x)
t = t.modpow(x, N)
s1 = s1 * t
s1.mod(N)
# r = N mod p^k
r = N % (p**k)
# s2 = s1 ^ (N/p^k)
s2 = s1.modpow(N//(p**k), N)
# J^alpha
J_alpha = JacobiSum(p,k,q).one()
for x in range(p**k):
if x % p == 0:
continue
t = J.sigma_inv(x)
t = t.modpow((r*x)//(p**k), N)
J_alpha = J_alpha * t
J_alpha.mod(N)
# S = s2 * J_alpha
S = (s2 * J_alpha).mod(N)
# Is S root of unity
exist, h = S.is_root_of_unity(N)
if not exist:
# composite!
return False, None
else:
# possible prime
if h%p!=0:
l_p = 1
else:
l_p = 0
return True, l_p
# in case of p=2 and k>=3
def APRtest_step4b(p, k, q, N):
print("Step 4b. (p^k, q = {0}^{1}, {2})".format(p,k,q))
J = calc_J3(p, k, q)
# initialize s1=1
s1 = JacobiSum(p,k,q).one()
# J3^Theta
for x in range(p**k):
if x % 8 not in [1,3]:
continue
t = J.sigma_inv(x)
t = t.modpow(x, N)
s1 = s1 * t
s1.mod(N)
# r = N mod p^k
r = N % (p**k)
# s2 = s1 ^ (N/p^k)
s2 = s1.modpow(N//(p**k), N)
# J3^alpha
J_alpha = JacobiSum(p,k,q).one()
for x in range(p**k):
if x % 8 not in [1,3]:
continue
t = J.sigma_inv(x)
t = t.modpow((r*x)//(p**k), N)
J_alpha = J_alpha * t
J_alpha.mod(N)
# S = s2 * J_alpha * J2^delta
if N%8 in [1,3]:
S = (s2 * J_alpha ).mod(N)
else:
J2_delta = calc_J2(p,k,q)
S = (s2 * J_alpha * J2_delta).mod(N)
# Is S root of unity
exist, h = S.is_root_of_unity(N)
if not exist:
# composite
return False, None
else:
# possible prime
if h%p!=0 and (pow(q,(N-1)//2,N) + 1)%N==0:
l_p = 1
else:
l_p = 0
return True, l_p
# in case of p=2 and k=2
def APRtest_step4c(p, k, q, N):
print("Step 4c. (p^k, q = {0}^{1}, {2})".format(p,k,q))
J2q = calc_J(p, k, q)
# s1 = J(2,q)^2 * q (mod N)
s1 = (J2q * J2q * q).mod(N)
# s2 = s1 ^ (N/4)
s2 = s1.modpow(N//4, N)
if N%4 == 1:
S = s2
elif N%4 == 3:
S = (s2 * J2q * J2q).mod(N)
else:
print("Error")
# Is S root of unity
exist, h = S.is_root_of_unity(N)
if not exist:
# composite
return False, None
else:
# possible prime
if h%p!=0 and (pow(q,(N-1)//2,N) + 1)%N==0:
l_p = 1
else:
l_p = 0
return True, l_p
# in case of p=2 and k=1
def APRtest_step4d(p, k, q, N):
print("Step 4d. (p^k, q = {0}^{1}, {2})".format(p,k,q))
S2q = pow(-q, (N-1)//2, N)
if (S2q-1)%N != 0 and (S2q+1)%N != 0:
# composite
return False, None
else:
# possible prime
if (S2q + 1)%N == 0 and (N-1)%4==0:
l_p=1
else:
l_p=0
return True, l_p
# Step 4
def APRtest_step4(p, k, q, N):
if p>=3:
result, l_p = APRtest_step4a(p, k, q, N)
elif p==2 and k>=3:
result, l_p = APRtest_step4b(p, k, q, N)
elif p==2 and k==2:
result, l_p = APRtest_step4c(p, k, q, N)
elif p==2 and k==1:
result, l_p = APRtest_step4d(p, k, q, N)
else:
print("error")
if not result:
print("Composite")
return result, l_p
def APRtest(N):
t_list = [
2,
12,
60,
180,
840,
1260,
1680,
2520,
5040,
15120,
55440,
110880,
720720,
1441440,
4324320,
24504480,
73513440
]
print("N=", N)
if N<=3:
print("input should be greater than 3")
return False
# Select t
for t in t_list:
et, q_list = e(t)
if N < et*et:
break
else:
print("t not found")
return False
print("t=", t)
print("e(t)=", et, q_list)
# Step 1
print("=== Step 1 ===")
g = gcd(t*et, N)
if g > 1:
print("Composite")
return False
# Step 2
print("=== Step 2 ===")
l = {}
fac_t = prime_factorize(t)
for p, k in fac_t:
if p>=3 and pow(N, p-1, p*p)!=1:
l[p] = 1
else:
l[p] = 0
print("l_p=", l)
# Step 3 & Step 4
print("=== Step 3&4 ===")
for q in q_list:
if q == 2:
continue
fac = prime_factorize(q-1)
for p,k in fac:
# Step 4
result, l_p = APRtest_step4(p, k, q, N)
if not result:
# composite
print("Composite")
return False
elif l_p==1:
l[p] = 1
# Step 5
print("=== Step 5 ===")
print("l_p=", l)
for p, value in l.items():
if value==0:
# try other pair of (p,q)
print("Try other (p,q). p={}".format(p))
count = 0
i = 1
found = False
# try maximum 30 times
while count < 30:
q = p*i+1
if N%q != 0 and isprime_slow(q) and (q not in q_list):
count += 1
k = v(p, q-1)
# Step 4
result, l_p = APRtest_step4(p, k, q, N)
if not result:
# composite
print("Composite")
return False
elif l_p == 1:
found = True
break
i += 1
if not found:
print("error in Step 5")
return False
# Step 6
print("=== Step 6 ===")
r = 1
for t in range(t-1):
r = (r*N) % et
if r!=1 and r!= N and N % r == 0:
print("Composite", r)
return False
# prime!!
print("Prime!")
return True
if __name__ == '__main__':
start_time = time.time()
APRtest(2**521-1) # 157 digit, 18 sec
# APRtest(2**1279-1) # 386 digit, 355 sec
# APRtest(2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077)
end_time = time.time()
print(end_time - start_time, "sec")
credit: https://github.com/wacchoz/APR_CL/blob/master/APR_CL.py
You only need to test odd numbers, except for 2 which you can test specially before the loop. This doesn't change the complexity, since it's a constant factor, but it reduces the time in half.
You should only test numbers up to math.sqrt(x). This changes the worst case complexity from O(n) to O(sqrt(n)).
You should stop as soon as you find a factor, rather than creating a list of all the x % i. This improves the best case complexity.
import math
def is_prime(x):
'''
Function to check if a number is prime
'''
if x == 2:
return True
if x % 2 == 0:
return False
for i in range(3, int(math.sqrt(x))+1, 2):
if x % i == 0:
return False
return True
Even better than checking all odd numbers is to check only prime numbers, using the Sieve of Eratosthenes.

problem of decryption data using RSA method

is there away to solve this problem even the code is work prefect for encrypted and decrypted the data when they are in same file, the problem happen when i divide the code into two parts, one part encryption and second part decryption, but still i'm getting wrong decryption data even i use same public key and n value was generated in encryption part.
suppose:
data='hello'
p=23
q=19
public key=(185,437)
private key=(533,437)
when i use the public key for decryption the data is wrong!! i have also try use private same also wrong!! any suggestion !
encryption code:
import random
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
def multiplicative_inverse(e, phi):
d = 0
x1 = 0
x2 = 1
y1 = 1
temp_phi = phi
while e > 0:
temp1 = temp_phi//e
temp2 = temp_phi - temp1 * e
temp_phi = e
e = temp2
x = x2- temp1* x1
y = d - temp1 * y1
x2 = x1
x1 = x
d = y1
y1 = y
if temp_phi == 1:
return d + phi
'''
Tests to see if a number is prime.
'''
def is_prime(num):
if num == 2:
return True
if num < 2 or num % 2 == 0:
return False
for n in range(3, int(num**0.5)+2, 2):
if num % n == 0:
return False
return True
def generate_keypair(p, q):
if not (is_prime(p) and is_prime(q)):
raise ValueError('Both numbers must be prime.')
elif p == q:
raise ValueError('p and q cannot be equal')
#n = pq
n = p * q
#Phi is the totient of n
phi = (p-1) * (q-1)
#Choose an integer e such that e and phi(n) are coprime
e = random.randrange(1, phi)
#Use Euclid's Algorithm to verify that e and phi(n) are comprime
g = gcd(e, phi)
while g != 1:
e = random.randrange(1, phi)
g = gcd(e, phi)
#Use Extended Euclid's Algorithm to generate the private key
d = multiplicative_inverse(e, phi)
#Return public and private keypair
#Public key is (e, n) and private key is (d, n)
return ((e, n), (d, n))
def encrypt(pk, plaintext):
#Unpack the key into it's components
key, n = pk
#Convert each letter in the plaintext to numbers based on the character using a^b mod m
cipher = [(ord(char) ** key) % n for char in plaintext]
#Return the array of bytes
return cipher
if __name__ == '__main__':
print ("RSA Encrypter/ Decrypter")
p = int(23)
q = int(19)
print ("Generating your public/private keypairs now . . .")
public, private = generate_keypair(p, q)
print ("Your public key is ", public ," and your private key is ", private)
message = str('hello')
encrypted_msg = encrypt(private, message)
print ("Your encrypted message is: ")
print (''.join(map(lambda x: str(x), encrypted_msg)))
decryption code:
def decrypt(k,pk, ciphertext):
#Unpack the key into its components
key=k
n = pk
#Generate the plaintext based on the ciphertext and key using a^b mod m
plain = [chr((ord(char) ** key) % n) for char in ciphertext]
return ''.join(plain)
if __name__ == '__main__':
'''
Detect if the script is being run directly by the user
'''
print ("RSA Encrypter/ Decrypter")
key = int(533)
n = int(437)
public=(key,n)
message = '271169420420218'
print ("Decrypting message with public key ", public ," . . .")
print ("Your message is:")
print (decrypt(key,n, message))
i'm using python 3.6 spyder

Why does the encryption/decryption in my RSA code not work?

I'm currently coding a simplified RSA algorithm for a project at school but can't get it to work.
I've based the code off of the formulae c = m^e(mod N) and (c^d)mod N. The encryption function works to produce what looks like a feasible output but when I put it into the decryption function it either doesn't return the message correctly or gives me this error:
ValueError: chr() arg not in range(0x110000)
My code:
import random
import math
def is_prime(x):
for i in range(2,int(math.sqrt(x))+1):
if x % i == 0:
return False
break
return True
def gcd(a, b):
if (b == 0):
return a
else:
return gcd(b, a % b)
def generate_p_and_q(p,q):
p_and_q = []
p_and_q.append(p)
p_and_q.append(q)
return p_and_q
def generate_phi(p,q):
p_and_q = generate_p_and_q(p,q)
phi = (p_and_q[0] - 1)*(p_and_q[1] - 1)
return phi
def generate_N(p,q):
p_and_q = generate_p_and_q(p,q)
N = (p_and_q[0])*(p_and_q[1])
return N
def generate_e(p,q):
phi = generate_phi(p,q)
with open('First500Primes.txt') as f:
lines = f.read().splitlines()
for i in lines:
if int(i) > 1 and int(i)< phi:
if gcd(int(i), phi) == 1:
e = int(i)
break
return e
def encrypt_RSA():
encrypted = []
message = input("Enter a message to encrypt:")
message.lower()
with open('First500Primes.txt') as f:
lines = f.read().splitlines()
valid = False
choice = input("Do you want to: \nA: enter a key \nB: use a random key?\n")
if choice.lower() == 'a':
p = int(input("Enter a key - this must be a prime number between 0 and 500:"))
q = int(input("Enter a key - this must be a prime number between 0 and 500:\n"))
while valid != True:
valid = is_prime(p) and is_prime(q)
if valid == False:
print("Your numbers were not prime!")
p = int(input("Enter a key - this must be a prime number between 0 and 500:"))
q = int(input("Enter a key - this must be a prime number between 0 and 500:\n"))
else:
x = random.randint(0, 499)
y = random.randint(0, 499)
p = int(lines[x])
q = int(lines[y])
generate_p_and_q(p,q)
e = generate_e(p,q)
N = generate_N(p,q)
for char in message:
encrypted.append((ord(char) ** e) % N)
result = ''
for i in encrypted:
result = result + str(i)
print("encrypted message: " + result)
info = [encrypted, N, e]
return (info)
encrypt_RSA()
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 calculate_d(a,m):
g,x,y = egcd(a,m)
if g != 1:
return None
else:
return x%m
def calculate_phi(N):
with open('First500Primes.txt') as f:
lines = f.read().splitlines()
for num in lines:
if N%int(num) == 0:
p = int(num)
q = N/int(num)
phi = (p-1)*(q-1)
return int(phi)
def decrypt_RSA():
encrypted = encrypt_RSA()
encrypted_message, N, e = encrypted[0], encrypted[1], encrypted[2]
print(N)
phi = calculate_phi(N)
d = calculate_d(phi,e)
print("D: " + str(d))
message = []
encrypted_message = (encrypted[0])
for c in encrypted_message:
m = (c**d) % N
print(m)
message.append(chr(m))
print(message)
decrypt_RSA()
I need the code to firstly encrypt the message with the encrypt function then decrypt it with the decrypt function, so the encrypted and original message should be displayed.
Could someone tell me whats wrong with my code (since I'm still in school, it may need to be simplified), any additional feedback would be greatly appreciated.
After a bit of debugging, the problem is that the function calculate_d() does not seem to calculate the right number. It is solved when we invert the params of one of your function. Change this line
d = calculate_d(phi, e)
to this:
d = calculate_d(e, phi)
That got it working for me.
Also, since you asked for suggestions to improve your code, I made a few (a lot) improvements. Some ideas:
I replaced the parts that read the prime number file with a prime number generator, but that is just because I didn't have the file at hand. Choose whichever you like best.
Invoke the main functions inside a if __name__ == '__main__':. Read about it here.
I moved the input prompts outside of the encryption code. Implement those parts as needed (random or prompting user for input) and just pass the result to the function for encryption.
My version:
def generate_primes():
"""
Generate an infinite sequence of prime numbers.
Sieve of Eratosthenes
Code by David Eppstein, UC Irvine, 28 Feb 2002
http://code.activestate.com/recipes/117119/
https://stackoverflow.com/a/568618/9225671
"""
# Maps composites to primes witnessing their compositeness.
# This is memory efficient, as the sieve is not "run forward"
# indefinitely, but only as long as required by the current
# number being tested.
D = {}
# The running integer that's checked for primeness
q = 2
while True:
if q not in D:
# q is a new prime.
# Yield it and mark its first multiple that isn't
# already marked in previous iterations
yield q
D[q * q] = [q]
else:
# q is composite. D[q] is the list of primes that
# divide it. Since we've reached q, we no longer
# need it in the map, but we'll mark the next
# multiples of its witnesses to prepare for larger
# numbers
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
def choose_p_and_q():
p_i = random.randint(0, 100)
q_i = random.randint(0, 100)
p = 0
q = 0
for i, n in enumerate(generate_primes()):
if i <= p_i:
p = n
if i <= q_i:
q = n
if i > p_i and i > q_i:
break
return p, q
def generate_n(p, q):
return p * q
def generate_phi(p, q):
return (p - 1) * (q - 1)
def generate_e(phi):
e = None
for n in generate_primes():
if math.gcd(n, phi) == 1:
e = n
if n >= phi:
if e is None:
raise ValueError('no suitable prime number found; reached {}'.format(n))
# return the highest prime number found
return e
def find_p_and_q_from_n(n):
for i in generate_primes():
if n % i == 0:
p = i
q, remainder = divmod(n, p)
if remainder == 0:
return p, q
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 calculate_d(phi, e):
g, x, _ = egcd(phi, e)
if g == 1:
return x % e
raise ValueError('no modular multiplicative inverse found')
def encrypt_rsa(msg):
p, q = choose_p_and_q()
n = generate_n(p, q)
phi = generate_phi(p, q)
e = generate_e(phi)
print()
print('ENCRYPT')
print('p ', p)
print('q ', q)
print('n ', n)
print('phi ', phi)
print('e ', e)
encrypted_list = []
for char in msg:
m = (ord(char) ** e) % n
encrypted_list.append(m)
print('msg ', list(msg))
print('encrypted_list', encrypted_list)
return encrypted_list, n, e
def decrypt_rsa(encrypted_list, n, e):
p, q = find_p_and_q_from_n(n)
phi = generate_phi(p, q)
d = calculate_d(e, phi)
print()
print('DECRYPT')
print('p ', p)
print('q ', q)
print('n ', n)
print('phi ', phi)
print('e ', e)
print('d ', d)
decrypted_list = []
for elem in encrypted_list:
m = (elem**d) % n
decrypted_list.append(chr(m))
print('decrypted_list', decrypted_list)
if __name__ == '__main__':
msg = input('Enter a message to encrypt:').strip()
data = encrypt_rsa(msg)
decrypt_rsa(*data)

Is my math or my variables wrong in my RSA example?

I was reading up on cryptography, specifically RSA(https://www.khanacademy.org/computing/computer-science/cryptography/modern-crypt/v/rsa-encryption-part-4), and decided to make an example for myself. However, even though I'm pretty sure I got my variables right, I think I got my math wrong. Can someone help me find the error? I tried to put comments everywhere I thought needed an explanation. Written in Python 3.5.2
#m^phi(n) mod n == 1 where m & n dont share a common factor
#since 1^k = 1, m^(k * phi(n)) mod n == 1, too.
#since 1*m = m, m* (m^(k * phi(n)) mod n) == m
#^^^^simplifies to m^(k * phi(n) + 1) mod n == m
#b/c m^(e*d) mod n = m
#m^(e*d) mod n == m^(k * phi(n) + 1) mod n
#e*d = k * phi(n) + 1
#d = (k * phi(n) + 1)/e
from fractions import gcd
import random
i = 1
j = 1
t = 1
def is_prime(a):
return all(a % i for i in range(2, a))
while True:
p1 = random.randrange(10.00000)#gens the 1st random prime
if is_prime(p1):
if p1 == 0 or p1 == 1:
i+=1
continue
else:
print("First Random Prime Found on attempt "+str(i)+": "+str(p1))
break
i+=1
while True:
p2 = random.randrange(10.00000)#gens the 1st random prime
if is_prime(p2):
if p2 == 0 or p2 == 1:
j+=1
continue
else:
print("First Random Prime Found on attempt "+str(j)+": "+str(p2))
break
j+=1
n = p1 * p2
print("n = p1 * p2 = "+str(n))
phi_n = (p1 - 1) * (p2 - 1)#phi(n) = how many numbers below n share no factors w/ n. Given Definition of a prime, phi(any_prime_num) is always any_prime_num - 1.
print("phi_n = (p1 - 1) * (p2 - 1) = "+str(phi_n))
while True:
e = random.randrange(10)#gens the 3rd random prime
if e % 2 != 0:
if phi_n % e == 0:
k+=1
continue
else:
print("Public Random Prime(is e)Found on attempt "+str(t)+": "+str(e))
break
k = random.randrange(e)
print("num used to find d(is k): "+str(k))
d = (k * phi_n + 1)/e
print("PRIVATE key(is d): "+str(d))
#pub_key = [n, e]
#priv_key = [d, k, p1, p2, phi_n]
m = input("Type an int: ")
if gcd(int(m), n) != 1:
quit() #b/c m & n must not share a common factor(apparently)
c = (int(m)**e) % n #cipher text(nums)
print("Encrypted: "+str(c))
u = (c**d) % n #SHOULD be decrypted text(more nums)
print("Decrypted: "+str(u))
if int(m) == int(u):
print("Successful!!")
else:
print("Unsuccessful....")

Categories

Resources