RSA encryption python not working with small primes - python

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.

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 python3 - decryption output not equivalent to message

I have been trying to create a basic encryption/decryption code for an input message (which is a number). However my decryption code does not produce the message. The e value was chosen to be 19 (its small bc its a proof of concept) and the two prime numbers that multiply to yield n are 41 and 29. I was able to find d to be 59 through a mod inverse code I found online. What could be going wrong?
# encryption function
def encrypt(msg):
encryption = (msg ** e) % n
return encryption
# decryption function
def decrypt(encrypt):
decryption = (encrypt ** d) % n
return decryption
(btw n is the modulus, e is the part of the public key and d is the part of the private key)
Your code is not much clear because i don't know from where and how you are getting the values of e,d and n. Try this basic implementation of RSA algorithm in Cryptography.
from decimal import Decimal
def gcd(a,b):
if b==0:
return a
else:
return gcd(b,a%b)
p = int(input('Enter the value of p = '))
q = int(input('Enter the value of q = '))
no = int(input('Enter the value of text = '))
n = p*q
t = (p-1)*(q-1)
for e in range(2,t):
if gcd(e,t)== 1:
break
for i in range(1,10):
x = 1 + i*t
if x % e == 0:
d = int(x/e)
break
ctt = Decimal(0)
ctt =pow(no,e)
ct = ctt % n
dtt = Decimal(0)
dtt = pow(ct,d)
dt = dtt % n
print('n = '+str(n)+' e = '+str(e)+' t = '+str(t)+' d = '+str(d)+' cipher text = '+str(ct)+' decrypted text = '+str(dt))

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.

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