RSA encryption in python - 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

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.

RSA implementation decryption/ encryption

I'm trying to implement RSA. But I've got a few problems with this. I´m trying to encrypt a String with 2 prime numbers.
p= 1606938044258990275541962092341162602522202993782792835301611
q= 3213876088517980551083924184682325205044405987565585670603103
First I do what has to be done for the RSA algorithm. After I've encrypted the String I tried to decrypt it as well. But the result is something like this: ÜŞϟʐͶz̽ć
def xgcd(a, b):
"""return (g, x, y) such that a*x + b*y = g = gcd(a, b)"""
x0, x1, y0, y1 = 0, 1, 1, 0
while a != 0:
q, b, a = b // a, a, b % a
y0, y1 = y1, y0 - q * y1
x0, x1 = x1, x0 - q * x1
return b, x0, y0
def genKeypair(p, q):
n = p * q
phiN = (p - 1) * (q - 1)
e = 65537
d = egcd(phiN, e)
return n, e, d
# encrypt message and return cipher
def encrypt(m, n, e):
m1 = ""
# Turn message string into ascii so it can be used for encryption
for x in range(len(m)):
m1 += '{0:03}'.format(ord(m[x]))
# encrypt
c = squareAndMultiply(int(m1), e, n)
print(c)
return c
# decrypt cipher and return message
def decrypt(c, n, d):
# decrypt c
m = squareAndMultiply(c, d, n) #% n
# put decryption result into ascii format and use ascii to decode it
m = str(m)
tmp = ""
message = ""
i = 0
if int(m[0] + m[1] + m[3]) > 255:
m = "0" + m
for x in range(len(m)):
tmp = tmp + m[x]
i += 1
if i % 3 == 0:
message += chr(int(tmp))
tmp = ""
return message
My square and multiply method looks like this:
def squareAndMultiply(x, n, m=0):
# turn exponent into binary
bin = '{0:b}'.format(n)
r = x
# loop through the string representing the binary form of the exponent while ignoring the leftmost bit and perform
# the appropriate operations on r
for i in range(1, len(bin)):
if (bin[i] == "0"):
r *= r % m
else:
r *= r % m
r *= x % m
# check for m being greater than 0, ignore it otherwise
if (m > 0):
return r % m
else:
return r
Has anyone an idea what could be wrong and what has to be changed, that the decryption gives the right answer?
In the code, the plaintext is encoded into a string by using the corresponding decimal ASCII-code (formatted to three digits) for each character, e.g.
ABCDEF -> 065066067068069070
Then, the string is converted to an integer m which is used as message and encrypted according to
This concept results in m becoming larger and larger with increasing plaintext length. At some point m violates the condition m < n and the algorithm fails (see RSA, Operation)!
The plaintext length at which the algorithm fails depends on n and can be determined as follows: In the example, n is a 121-digit number. Because 121/3 = 40.33..., a maximum of 40 characters can be encrypted without violating the condition m < n, i.e. from incl. 41 the encryption will generally fail. This can be verified with the following code:
p = 1606938044258990275541962092341162602522202993782792835301611
q = 3213876088517980551083924184682325205044405987565585670603103
n = p * q
phiN = (p - 1) * (q - 1)
e = 65537
d = egcd(phiN, e)[2]
encrypted = encrypt('0123456789012345678901234567890123456789', n, e); # will succeed
#encrypted = encrypt('01234567890123456789012345678901234567890', n, e); # will fail
decrypted = decrypt(encrypted, n, d);
print('>' + decrypted + '<')
A possible solution to this problem is to divide the plaintext into blocks with the same number of characters (the last block usually contains fewer characters). This number should correspond to the maximum possible number of characters, so that the condition m < n is not violated (= 40 in the posted example). Then each block is individually encoded and encrypted (in the same way as before).

Generating and using RSA keys with 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.

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

Categories