Generating and using RSA keys with Python - python

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.

Related

Python program seems to run forever without outputting in terminal

I have been working on a library to implement the RSA encryption method, and this file (along with others I have been working on) do not output, but instead after executing the script only output a blank line in terminal. I have run it through an autograder, and it times out. Below is the code for the library, but something tells me my issue could be an interpreter issue or something outside of the file itself. It looks like it could be getting stuck before reaching a return or output statement. I've also included a screenshot of the terminal output.
import stdio
import stdrandom
import sys
# Generates and returns the public/private keys as a tuple (n, e, d). Prime numbers p and q
# needed to generate the keys are picked from the interval [lo, hi).
def keygen(lo, hi):
primes = []
for i in range(lo, hi):
if _primes(0, i):
primes += [i]
ptemp = stdrandom.uniformInt(0, len(primes))
qtemp = stdrandom.uniformInt(0, len(primes))
p = primes[ptemp]
q = primes[qtemp]
n = p * q
m = (p - 1) * (q - 1)
while True:
e = stdrandom.uniformInt(2, m)
if e % m == 0 and m % e != 0:
break
d = 0
for a in range(1, m):
if (e * a) % m == 1:
d = a
break
return n, e, d
# Encrypts x (int) using the public key (n, e) and returns the encrypted value.
def encrypt(x, n, e):
return (x ** e) % n
# Decrypts y (int) using the private key (n, d) and returns the decrypted value.
def decrypt(y, n, d):
return (y ** d) % n
# Returns the least number of bits needed to represent n.
def bitLength(n):
return len(bin(n)) - 2
# Returns the binary representation of n expressed in decimal, having the given width, and padded
# with leading zeros.
def dec2bin(n, width):
return format(n, '0%db' % (width))
# Returns the decimal representation of n expressed in binary.
def bin2dec(n):
return int(n, 2)
# Returns a list of primes from the interval [lo, hi).
def _primes(lo, hi):
primes = []
for p in range(lo, hi + 1):
j = 2
f = 1
while(j * j <= p):
if(p % j == 0):
f = 0
break
j = j + 1
if(f == 1):
primes += [p]
return primes
# Returns a list containing a random sample (without replacement) of k items from the list a.
def _sample(a, k):
b = a.copy()
c = b[0:k]
stdrandom.shuffle(c)
return c
# Returns a random item from the list a.
def _choice(a):
random = stdrandom.uniformInt(0, len(a))
return random
# Unit tests the library [DO NOT EDIT].
def _main():
x = ord(sys.argv[1])
n, e, d = keygen(25, 100)
encrypted = encrypt(x, n, e)
stdio.writef('encrypt(%c) = %d\n', x, encrypted)
decrypted = decrypt(encrypted, n, d)
stdio.writef('decrypt(%d) = %c\n', encrypted, decrypted)
width = bitLength(x)
stdio.writef('bitLength(%d) = %d\n', x, width)
xBinary = dec2bin(x, width)
stdio.writef('dec2bin(%d) = %s\n', x, xBinary)
stdio.writef('bin2dec(%s) = %d\n', xBinary, bin2dec(xBinary))
if __name__ == '__main__':
_main()
As #iz_ suggests, you have an infinite loop in your code. This code:
while True:
e = stdrandom.uniformInt(2, m)
if e % m == 0 and m % e != 0:
break
will never exit because e will always be less than m, and therefore e % m == 0 will always be False. The loop won't exit until e % m == 0 is True, which will never happen.

How to calculate RSA private key in Python

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

RSA encryption python not working with small primes

I have implemented RSA encryption and decryption code which is working for values p,q,d = 61,53,17. I took these values as they are mentioned in wikipedia. I beleive that p and q should be prime and d is chosen such that d and phi(n) are relatively prime.
If I change the values to p,q,d = 3,17,19, my decryption is not working. Can you please help me with this? Here is my code:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
def main():
str = 'computer'
p,q,d = 61,53,17
#p,q,d = 3,17,19
cipher_text = list()
plain_text = list()
for c in str:
cipher_char = EncryptCharRSA(c, p, q ,d)
cipher_text.append(cipher_char)
for x in cipher_text:
plain_char = DecryptCharRSA(x, p, q, d)
plain_text.append(plain_char)
print ('Original Message: ', str)
print ('Encrypted Message(UTF-8 Unicode characters) : ', end='')
for element in cipher_text:
print(element,end = '')
print ('\nDecrypted Message: ', end='')
for element in plain_text:
print(element,end='')
def EncryptCharRSA(msg , p, q, d):
n = p * q
phi = (p-1) * (q-1)
cipher_no = 0
cipher_char = ''
for c in msg:
# conver char to ascii for calculation
cipher_no = (ord(c)** d) % n
cipher_char = chr(cipher_no)
return cipher_char
#print (cipher_no)
#plain_no = (cipher_no ** d) % n
def DecryptCharRSA(msg,p, q,d):
n = p * q
phi = (p-1) * (q-1)
e = ModularMultiplicativeInverse(d,phi)
for c in msg:
plain_no = (ord(c) ** e) % n
plain_char = chr(plain_no)
return plain_char
# Get modular multiplicative inverse
def ModularMultiplicativeInverse(d,n):
i = 1
while True:
if (d * i) % n == 1:
return i
i = i + 1
if __name__ == '__main__' : main()
What you call d is actually e the public exponent and what you call e is actually d the private exponent.
Naming aside, your problem is that you're encrypting plaintext character code points that are larger than or equal to n. If they are, then you're actually encrypting not ord("A") (=65), but rather ord("A") % n. For small n as in your case this would lead to unrecoverable ciphertext:
>>> n = 3 * 17 # 51
>>> ord("A")
65
>>> ord("A") % n
14
And that is exactly that you would be able to decrypt. RSA is not something that can be used to encrypt arbitrarily big data. Normally, you would combine it with a secure and fast block cipher such as AES through hybrid encryption.

Simple RSA code

Hi I am trying to create a working RSA program, but on a very small level, I am having problems encrypting and decrypting with this code, can someone help me figure out what is wrong? I have tried doing this many different ways, but this way seems to be the right math, so I believe it might just be my lack of coding skills? Thanks
import random, math
def RandomPrime():
prime = False
while prime == False:
n = 2
while n % 2 == 0:
n = random.randint(10000, 100000)
s = math.trunc(n**0.5)
s = int(s)
x = 3
# While n doesn't exactly divide to equal 0, and x is less then the sqrt of n
while ( n % x != 0 ) and (x <= s):
x = x + 2
# if n is greater than s, it means it has run out of numbers to test, so is prime
if x > s:
prime = True
return n
def Modulus(p, q):
M = p * q
return M
def Totient(p, q):
T = ((p-1) * (q-1))
return T
def Pubkey(T):
prime = False
while prime == False:
n = 2
while n % 2 == 0:
n = random.randint(3, T)
s = math.trunc(n**0.5)
s = int(s)
x = 3
# While
while ( n % x != 0 ) and (x <= s):
x = x + 2
if x > s:
prime = True
return n
def privkey( T, n):
y = math.fmod(1, T)
d = float((y / n))
return d
# z is my encyption in this scenario
z = 8
# I generate p and q, using my random prime generator, i used low primes in
# this example just to see if it would work but it is still not showing reults
p = RandomPrime()
q = RandomPrime()
print(p, q)
#This creates the modulus
M = Modulus(p, q)
print(M)
# Eulier's totient
T = Totient(p, q)
print(T)
#Pub key creation
n = Pubkey(T)
print(n)
#Priv key creation
d = privkey(n, T)
print(d)
enc = (pow(z, n)) % M
print('enc: ', enc)
dec = (pow(enc, d)) % M
print('dec: ', dec)
Your privkey function appears wrong - I'm guessing you saw the definition of RSA's private key value as something like:
the value "e" such that e * d = 1 mod Phi(N)
However in this case, 1 mod Phi(N) does not mean The remainder when 1 is divided by Phi(N) (which appears to be the way you have translated it into code, based on your use of math.fmod(1, T), but in fact should be read more like:
the value "e" such that (e * d) mod Phi(N) = 1
This value is generally calculated using the Extended Euclidean Algorithm. An example Python implementation is here.
It's also worth noting that you seem to be defining privkey(T, n) but calling it as privkey(n, T).
Check my blog which in detail contains the implementation of the following using python:
MD5 Secure hash Algorithm RFC 1321, RSA public Key cryptography RFC 3447, OpenPGP RFC 4880
def keyGen():
''' Generate Keypair '''
i_p=randint(0,20)
i_q=randint(0,20)
# Instead of Asking the user for the prime Number which in case is not feasible,
# generate two numbers which is much highly secure as it chooses higher primes
while i_p==i_q:
continue
primes=PrimeGen(100)
p=primes[i_p]
q=primes[i_q]
#computing n=p*q as a part of the RSA Algorithm
n=p*q
#Computing lamda(n), the Carmichael's totient Function.
# In this case, the totient function is the LCM(lamda(p),lamda(q))=lamda(p-1,q-1)
# On the Contrary We can also apply the Euler's totient's Function phi(n)
# which sometimes may result larger than expected
lamda_n=int(lcm(p-1,q-1))
e=randint(1,lamda_n)
#checking the Following : whether e and lamda(n) are co-prime
while math.gcd(e,lamda_n)!=1:
e=randint(1,lamda_n)
#Determine the modular Multiplicative Inverse
d=modinv(e,lamda_n)
#return the Key Pairs
# Public Key pair : (e,n), private key pair:(d,n)
return ((e,n),(d,n))
Blog Link :Python Cryptography
Github Link : Python Cryptography

RSA encryption in python

I decided to write a simple RSA encryption implementation in Python, but every time I run it it prints the error IndexError: list out of range when it's decrypting and in find_key.
Here's the error:
p 937
q 353
n 330761
phi 329472
e 5
d 264609
Traceback (most recent call last):
File "rsa.py", line 94, in
print dec_rsa(b, d, n)
File "rsa.py", line 88, in dec_rsa
char_array.append(decrypt_byte(i, d, n))
File "rsa.py", line 77, in decrypt_byte
return find_key(alpha, (c**d)%n)
File "rsa.py", line 67, in find_key
return [k for k, v in dic.iteritems() if v == val][0]
IndexError: list index out of range
The code:
import fractions, sys, random, math
def isPrime( no ):
if no < 2: return False
if no == 2: return True
if not no&1: return False
for x in range(3, int(no**0.5)+1, 2):
if no%x == 0:
return False
return True
def primes_range(low, high):
primes = []
for i in range(high-low):
if isPrime(i+low):
primes.append(i+low)
return primes
let = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789~!##$%^&*()_+'";:[]/<>,."
a, alpha = 2, {}
for i in let:
alpha[i] = a
a+=1
Low = 29
High = 1000
p = random.choice(primes_range(Low, High))
q = random.choice(primes_range(Low, High))
while p == q:
q = random.choice(primes_range(Low, High))
print "p ",p
print "q ",q
#p = 104729
#q = 3
p, q = int(p), int(q)
n = p*q
phi = (p-1)*(q-1)
print "n ",n
print "phi ",phi
for i in range(2, q if q>p else p):
if fractions.gcd(i, phi) == 1:
e = i
break
print "e ",e
def egcd(a,b):
u, u1 = 1, 0
v, v1 = 0, 1
while b:
q = a // b
u, u1 = u1, u - q * u1
v, v1 = v1, v - q * v1
a, b = b, a - q * b
return u, v, a
def modInverse(e, phi):
return egcd(e, phi)[0]%n
d = modInverse(e, n)
print "d ",d
def find_key(dic, val):
#print "val ",val
#print "dic ",list(dic.iteritems())
return [k for k, v in dic.iteritems() if v == val][0]
def encrypt_byte(byte, e, n):
try:
m = alpha[byte]
except:
m = int(byte)
return (m**e)%n
def decrypt_byte(c, d, n):
return find_key(alpha, (c**d)%n)
def enc_rsa(string, e, n):
char_array = []
for i in range(len(string)):
char_array.append(encrypt_byte(alpha[string[i]], e, n))
return char_array
def dec_rsa(enc_arr, d, n):
char_array = []
for i in enc_arr:
char_array.append(decrypt_byte(i, d, n))
return ''.join(char_array)
a = "hello, world"
b = enc_rsa(a, e, n)
#print b
print dec_rsa(b, d, n)
I hope you're enjoying learning Python!
A couple of things:
(1) Your isPrime is broken: it thinks 1 is prime, 2 and 3 aren't, but all of 25, 35, 121, 143, 289, 323, 529, 841, 899 are. Getting a composite will lead to problems.
(2) You also don't check to see that p != q.
(3) Your alpha[str(byte)] should be alpha[byte] (otherwise you'll get "96llo, worl5").
(4) You're taking the wrong multiplicative modular inverse. You want modInverse(e, phi(n)), not modInverse(e, n); see this worked example.
After fixing those, it seems to work for me.
The following aren't bugs, but suggestions: you should probably use pow(c,d,n) rather than (c**d)%n; for large numbers the former will be much faster. As well, if you want to turn a letter into a number, and you don't really care what number, you could use the "ord"/"chr" functions, and not even need a dictionary. In any case, you might want to swap the keys and values in your dictionary: right now your find_key might as well be using a list, as you're simply searching over all the k,v pairs until you find a match.
Hope that helps!
The implementation of RSA can be further simplified as follows:
1.Choose two different large primes, here for the sake of simplicity let's choose p=937, q=353, as done in the example
2.Compute n = p*q
3.Compute Euler Totient φ(n) ≡ (p-1)*(q-1)
4.Choose the public key e as coprime with φ(n), for simplicity, let's choose e=5, which is a prime
5.Compute the private key d, s.t. d*e ≡ 1 (mod φ(n)), using the multiplicative inverse algorithm (extended Euclidean) from here:
Compute multiplicative inverse of a modulo n
# solution t to a*t ≡ 1 (mod n)
def multiplicative_inverse(a, n):
t, newt = 0, 1
r, newr = n, a
while newr != 0:
q = r // newr
t, newt = newt, t - q * newt
r, newr = newr, r - q * newr
if t < 0:
t = t + n
return t
Python code for steps 1-5:
p, q = 937, 353 # use large primes here
n = p*q
φ = (p-1)*(q-1)
e = 5 # choose public key e as a prime, s.t., gcd(φ, e) = 1
d = multiplicative_inverse(e, φ) # private key d
print(d)
# 131789
6.Encrypt the message (plaintext) with the receiver's public key (e) at sender's end
7.Decrypt the ciphertext received at the receiver end with his private key (d)
The following code shows how the encryption / decryption can be done:
def rsa_encrypt(plain_text, e, n):
# ideally we should convert the plain text to byte array and
# then to a big integer which should be encrypted, but here for the sake of
# simplicity character-by-character encryption is done, which will be slow in practice
cipher_text = [ord(x)**e % n for x in plain_text]
return cipher_text
def rsa_decrypt(cipher_text, d, n):
decoded_text = ''.join([chr(x**d % n) for x in cipher_text])
return decoded_text
Now, let's use the above functions for encryption / decryption:
plain_text = 'Hello world'
cipher_text = rsa_encrypt(plain_text, e, n)
print(cipher_text)
# [296543, 169726, 215626, 215626, 293167, 147571, 122732, 293167, 217253, 215626, 102687]
decoded_text = rsa_decrypt(cipher_text, d, n)
decoded_text
# Hello world

Categories