fix of python rsa algorithm - python

I was doing a previous thread question of euclidean algorithm and multiplicative inverse and then I understood that is better post the complete code and do the rigth question: I am doing python rsa implemmentation and need to fix it because it is outputting wrong results.
The code:
import fractions #gcd
def generateRSAKeys(p, q):
"Generate RSA Public and Private Keys from prime numbers p & q"
n = p * q #is used as the modulus for both the public and private keys
etf = (p - 1) * (q - 1) #Euler's totient function. etf
# Generate a number e so that gcd(n, e) = 1, start with e = 3
e = 3
while 1:
if fractions.gcd(e, etf) == 1 and 1<e and e<etf:
break
else:
e = e + 1
#e is released as the public key exponent.
# start with a number d = etf/e will be atleast 1
#e*d == 1%etf #multiplicative inverse of etf
d = (e**(etf-2)) % etf
# Return a tuple of public and private keys
return ((n,e), (n,d))
#http://en.wikipedia.org/wiki/RSA_%28algorithm%29
if __name__ == "__main__":
print "RSA Encryption algorithm...."
p = long(raw_input("Enter the value of p (prime number):"))
q = long(raw_input("Enter the value of q (prime number):"))
print "Generating public and private keys...."
(publickey, privatekey) = generateRSAKeys(p, q)
print "Public Key (n, e) =", publickey
print "Private Key (n, d) =", privatekey
n, e = publickey
n, d = privatekey
m = 34 #some message
print "0<m<n m=", m
print "0<m<n n=" , n
#then computes ciphertext c
c = (m**e)%n
print "Encrypted number using public key =", c
#recovering
m = (c**d)%n
print "Decrypted (Original) number using private key =", m

Related

RSA key generation, signature and verification does not give expected results

For educational purposes, I'm trying to implement the RSA key generation and then signing a message with subsequent verification. Although, I'm following the general formulas for the key generation, eventually the verification returns False.
import hashlib
def fast_modular_exponentiation(a, b, n):
result = 1
while b > 0:
if b % 2 == 1:
result = (result * a) % n
a = (a * a) % n
b //= 2
return result
def generate_RSA_keys(p, q):
n = p * q
phi = (p - 1) * (q - 1)
e = 65537
d = fast_modular_exponentiation(e, phi - 1, n)
return e, d, n
def RSA_signature_generation(message, d, n):
digest = int.from_bytes(hashlib.sha256(message).digest(), byteorder='big')
signature = fast_modular_exponentiation(digest, d, n)
return signature
def RSA_signature_verification(message, e, n, signature):
digest = int.from_bytes(hashlib.sha256(message).digest(), byteorder='big')
verification = fast_modular_exponentiation(signature, e, n) is digest
return verification
# generate RSA keys
e, d, n = generate_RSA_keys(23, 47)
# message to be signed
message = b"hello world"
# generate RSA signature
signature = RSA_signature_generation(message, d, n)
# verify RSA signature
verification = RSA_signature_verification(message, e, n, signature)
print(verification) # False
Running the code yields False instead of True.
For everybody that comes up with the same problem, thanks to the above comments I could find a working solution:
import hashlib
from Crypto.Util.number import getPrime
def fast_modular_exponentiation(a, b, n):
result = 1
while b > 0:
if b % 2 == 1:
result = (result * a) % n
a = (a * a) % n
b //= 2
return result
def extended_euclidean_algorithm(exp_encrypt, totient):
do, dn = 0, 1
r_old = totient # dont overwrite original value, keep for later
nr = exp_encrypt
while nr > 0:
q = r_old // nr # thats the quotient
do, dn = dn, do - q * dn
r_old, nr = nr, r_old - q * nr
return do % totient if r_old == 1 else None
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def generate_RSA_keys():
# select target security
t = 2048
# select a public exponent e
e = 65537
while True:
# select a prime p of length t/2
p = getPrime(t // 2)
# select a prime q of length t/2
q = getPrime(t // 2)
# compute n = pq
n = p * q
# compute phi(n) = (p-1)(q-1)
phi = (p - 1) * (q - 1)
# check if gcd(e, phi(n)) = 1
if gcd(e, phi) == 1:
break
# compute d with the extended Euclidean algorithm
d = extended_euclidean_algorithm(e, phi)
# return the public key (e, n) and the private key (d, n)
return e, d, n
def rsa_encryption(message, e, n):
return fast_modular_exponentiation(message, e, n)
def rsa_decryption(ciphertext, d, n):
return fast_modular_exponentiation(ciphertext, d, n)
def rsa_signature_generation(message, d, n):
digest = int.from_bytes(hashlib.sha256(message).digest(), byteorder='big')
signature = fast_modular_exponentiation(digest, d, n)
return signature
def rsa_signature_verification(message, e, n, signature):
digest = int.from_bytes(hashlib.sha256(message).digest(), byteorder='big')
verification = fast_modular_exponentiation(signature, e, n) == digest
return verification
if __name__ == '__main__':
# generate RSA keys
e, d, n = generate_RSA_keys()
print(e)
print(d)
print(n)
# message to be signed
message = b"hello world"
# convert message to integer
message_int = int.from_bytes(message, byteorder='big')
# encrypt the message
ciphertext = rsa_encryption(message_int, e, n)
print(int.from_bytes(message, byteorder='big'))
print(ciphertext)
# decrypt the message
decrypted_message = rsa_decryption(ciphertext, d, n)
print(decrypted_message)
# convert the decrypted message to bytes
decrypted_message_bytes = decrypted_message.to_bytes((decrypted_message.bit_length() + 7) // 8, byteorder='big')
print(decrypted_message_bytes)
print("=========================================")
# generate the signature
signature = rsa_signature_generation(message, d, n)
print(signature)
# verify the signature
verification = rsa_signature_verification(message, e, n, signature)
print(verification)

Implementation of binomial option pricing closed form expression

I am trying to implement this formula in python:
This is the code I think came up with:
N = 2
S0 = 10
K = 9
T = 2
r = 0.2
import math
def combos(n, i):
return math.factorial(n) / (math.factorial(n-i)*math.factorial(i))
def binom(S0, K , T, r, N, type_ = 'call'):
dt = T/N
# u = np.exp(sigma * np.sqrt(dt))
# d = np.exp(-sigma * np.sqrt(dt))
# p = ( np.exp(r*dt) - d ) / ( u - d )
u = 1.5
d = 0.5
p = 0.2
value = 0
for i in range(N+1):
node_prob = combos(N, i)*p**i*(1-p)**(N-i)
ST = S0*(u)**i*(d)**(N-i)
print(ST)
if type_ == 'call':
value += max(ST-K,0) * node_prob
elif type_ == 'put':
value += max(K-ST, 0) * node_prob
else:
raise ValueError("type_ must be 'call' or 'put'" )
return value*(1/(1+r)**T)
binom(S0, K, T, r, N)
But when I try to calculate the option price above I don't get 4.59375 but instead get 0.3750. As you can see i don't have to calculate the u,d and p as they are given. So it my code incorrect or is the example wrong?

Define a one-parameter grant print_for (n), n represents the range over which the friend number will be printed

Define a one-parameter grant print_for (n), n represents the range over which the friend number will be printed. For n = 10,000 results, five pairs of friendly numbers: 220 and 284, 1184 and 1210, 2620 and 2924, 5020 and 5564, and 6232 and 6368.
from math import *
def sum_of_divisor (a):
pom = 1
for i in range (2, int (sqrt(a)) + 1):
if a % i == 0:
pom += i
if i != a // i:
pom += a // i
return pom
def friendly_n (a, b):
result = "false"
if(a == sum_of_divisor(b) and sum_of_divisor(a) == b):
result = "true"
return result
a = 284
b = 220
def write_friendly(n)
I don't know how to write a function to print friendly numbers.
Please help
Following your comments, perhaps this helps:
if friendly_n(a, b) == 'true': # a and b are friendly, according to friendly_n
string_to_print = str(a) + ' and ' + str(b) + ' are friendly'
print(string_to_print)
?

Python pow() function returns wrong answer

I am creating a basic RSA encryption program without using an RSA library that takes a secret message, converts each character in the string to its ASCII value, encrypts with a public key and concatenates the values, and then decrypts it using a private key and returns it to a string.
All with the principle of cipher = pow(plain,e,n) and plain = pow(cipher,d,n). My issue is that when the numbers get very large as I need d and n to be 16 digits minimum, the pow() function seems to result in an error in calculation that yields an ASCII value that is out of range to convert to a character. I've been struggling to figure out where I'm going wrong for days now. Any help is appreciated. Code below:
from random import randrange, getrandbits
def is_prime(n, k=128):
# Test if n is not even.
# But care, 2 is prime !
if n == 2 or n == 3:
return True
if n <= 1 or n % 2 == 0:
return False
# find r and s
s = 0
r = n - 1
while r & 1 == 0:
s += 1
r //= 2
# do k tests
for q in range(k):
a = randrange(2, n - 1)
x = pow(a, r, n)
if x != 1 and x != n - 1:
j = 1
while j < s and x != n - 1:
x = pow(x, 2, n)
if x == 1:
return False
j += 1
if x != n - 1:
return False
return True
def generate_prime_candidate(length):
# generate random bits
p = getrandbits(length)
#p = randrange(10**7,9*(10**7))
# apply a mask to set MSB and LSB to 1
p |= (1 << length - 1) | 1
return p
def generate_prime_number(length=64):
p = 4
# keep generating while the primality test fail
while not is_prime(p, 128):
p = generate_prime_candidate(length)
return p
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
def generate_keypair(p, q):
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 = randrange(1,65537)
g = gcd(e, phi)
while g != 1:
e = randrange(1,65537)
g = gcd(e, phi)
d = multiplicative_inverse(e, phi)
return ((e, n), (d, n))
def multiplicative_inverse(e, phi):
d = 0
k = 1
while True:
d = (1+(k*phi))/e
if((round(d,5)%1) == 0):
return int(d)
else:
k+=1
def encrypt(m,public):
key, n = public
encrypted = ''
print("Your original message is: ", m)
result = [(ord(m[i])) for i in range(0,len(m))]
encryption = [pow(result[i],key,n) for i in range(0,len(result))]
for i in range(0,len(encryption)):
encrypted = encrypted + str(encryption[i])
#encrypted = pow(int(encrypted),key,n)
print("Your encrypted message is: ", encrypted)
#return result,encrypted
return encrypted, encryption
def decrypt(e,c,private):
key, n = private
print("Your encrypted message is: ", c)
print(e)
decryption = [pow(e[i],key,n) for i in range(0,len(e))]
print(decryption)
result = [chr(decryption[i])for i in range(0,len(decryption)) ]
decrypted = ''.join(result)
print("Your decrypted message is: ",decrypted)
return result,decrypted
def fastpow(x,y,p):
res = 1
x = x%p
while(y>0):
if((y&1) == 1):
res = (res*x)%p
y = y>>1
x = (x*x)%p
return res
message = input("Enter your secret message: ")
p1 = generate_prime_number()
p2 = generate_prime_number()
public, private = generate_keypair(p1,p2)
print("Your public key is ", public)
print("Your private key is ", private)
encrypted,cipher = encrypt(message,public)
decrypt(cipher,encrypted,private)
Traceback:
File "<ipython-input-281-bce7c44b930c>", line 1, in <module>
runfile('C:/Users/Mervin/Downloads/group2.py', wdir='C:/Users/Mervin/Downloads')
File "C:\Users\Mervin\Anaconda3\lib\site-packages\spyder\util\site\sitecustomize.py", line 705, in runfile
execfile(filename, namespace)
File "C:\Users\Mervin\Anaconda3\lib\site-packages\spyder\util\site\sitecustomize.py", line 102, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/Mervin/Downloads/group2.py", line 125, in <module>
decrypt(cipher,encrypted,private)
File "C:/Users/Mervin/Downloads/group2.py", line 100, in decrypt
result = [chr(decryption[i])for i in range(0,len(decryption)) ]
File "C:/Users/Mervin/Downloads/group2.py", line 100, in <listcomp>
result = [chr(decryption[i])for i in range(0,len(decryption)) ]
OverflowError: Python int too large to convert to C long
Your method multiplicative_inverse is not correct. I'm not certain what you are doing in that method with the round method and floating point division, but even if you got that part correct it would be too slow anyway, requiring O(φ) steps. The usual method for computing modular multiplicative inverses is an adaptation of the extended Euclidean algorithm, which runs in O(log(φ)2) steps. Here is a straightforward mapping from the psuedocode in the Wikipedia article to python 3 code:
def multiplicative_inverse(a, n):
t, newt = 0, 1
r, newr = n, a
while newr:
quotient = r // newr
t, newt = newt, t - quotient * newt
r, newr = newr, r - quotient * newr
if r > 1:
raise ZeroDivisionError("{} is not invertible".format(a))
if t < 0:
t = t + n
return t

Sympy seems to break down with higher numbers

I've been playing around with sympy and decided to make an arbitrary equations solver since my finance class was getting a little dreary. I wrote a basic framework and started playing with some examples, but some work and some don't for some reason.
from sympy import *
import sympy.mpmath as const
OUT_OF_BOUNDS = "Integer out of bounds."
INVALID_INTEGER = "Invalid Integer."
INVALID_FLOAT = "Invalid Float."
CANT_SOLVE_VARIABLES = "Unable to Solve for More than One Variable."
CANT_SOLVE_DONE = "Already Solved. Nothing to do."
# time value of money equation: FV = PV(1 + i)**n
# FV = future value
# PV = present value
# i = growth rate per perioid
# n = number of periods
FV, PV, i, n = symbols('FV PV i n')
time_value_money_discrete = Eq(FV, PV*(1+i)**n)
time_value_money_continuous = Eq(FV, PV*const.e**(i*n))
def get_sym_num(prompt, fail_prompt):
while(True):
try:
s = input(prompt)
if s == "":
return None
f = sympify(s)
return f
except:
print(fail_prompt)
continue
equations_supported = [['Time Value of Money (discrete)', [FV, PV, i, n], time_value_money_discrete],
['Time Value of Money (continuous)',[FV, PV, i, n], time_value_money_continuous]]
EQUATION_NAME = 0
EQUATION_PARAMS = 1
EQUATION_EXPR = 2
if __name__ == "__main__":
while(True):
print()
for i, v in enumerate(equations_supported):
print("{}: {}".format(i, v[EQUATION_NAME]))
try:
process = input("What equation do you want to solve? ")
if process == "" or process == "exit":
break
process = int(process)
except:
print(INVALID_INTEGER)
continue
if process < 0 or process >= len(equations_supported):
print(OUT_OF_BOUNDS)
continue
params = [None]*len(equations_supported[process][EQUATION_PARAMS])
for i, p in enumerate(equations_supported[process][EQUATION_PARAMS]):
params[i] = get_sym_num("What is {}? ".format(p), INVALID_FLOAT)
if params.count(None) > 1:
print(CANT_SOLVE_VARIABLES)
continue
if params.count(None) == 0:
print(CANT_SOLVE_DONE)
continue
curr_expr = equations_supported[process][EQUATION_EXPR]
for i, p in enumerate(params):
if p != None:
curr_expr = curr_expr.subs(equations_supported[process][EQUATION_PARAMS][i], params[i])
print(solve(curr_expr, equations_supported[process][EQUATION_PARAMS][params.index(None)]))
This is the code I have so far. I guess I can strip it down to a basic example if need be, but I was also wondering if there was a better way to implement this sort of system. After I have this down, I want to be able to add arbitrary equations and solve them after inputting all but one parameter.
For example, if I put in (for equation 0), FV = 1000, PV = 500, i = .02, n is empty I get 35.0027887811465 which is the correct answer. If I redo it and change FV to 4000, it returns an empty list as the answer.
Another example, when I input an FV, PV, and an n, the program seems to hang. When I input small numbers, I got RootOf() answers instead of a simple decimal.
Can anyone help me?
Side note: I'm using SymPy 0.7.6 and Python 3.5.1 which I'm pretty sure are the latest
This is a floating point accuracy issue. solve by default plugs solutions into the original equation and evaluates them (using floating point arithmetic) in order to sort out false solutions. You can disable this by setting check=False. For example, for Hugh Bothwell's code
for fv in range(1870, 1875, 1):
sols = sp.solve(eq.subs({FV:fv}), check=False)
print("{}: {}".format(fv, sols))
which gives
1870: [66.6116466112007]
1871: [66.6386438584579]
1872: [66.6656266802551]
1873: [66.6925950919998]
1874: [66.7195491090752]
I don't have an answer, but I do have a much simpler demonstration case ;-)
import sympy as sp
FV, n = sp.symbols("FV n")
eq = sp.Eq(FV, sp.S("500 * 1.02 ** n"))
# see where it breaks
for fv in range(1870, 1875, 1):
sols = sp.solve(eq.subs({FV:fv}))
print("{}: {}".format(fv, sols))
which produces
1870: [66.6116466112007]
1871: [66.6386438584579]
1872: []
1873: []
1874: []
At a guess this is where the accuracy breaks down enough that it can't find a verifiable solution for n?
Also, while poking at this I did a fairly extensive rewrite which you may find useful. It does pretty much the same as your code but in a much more loosely-coupled fashion.
import sympy as sp
class Equation:
def __init__(self, label, equality_str, eq="=="):
self.label = label
# parse the equality
lhs, rhs = equality_str.split(eq)
self.equality = sp.Eq(sp.sympify(lhs), sp.sympify(rhs))
# index free variables by name
self.vars = {var.name: var for var in self.equality.free_symbols}
def prompt_for_values(self):
# show variables to be entered
var_names = sorted(self.vars, key=str.lower)
print("\nFree variables are: " + ", ".join(var_names))
print("Enter a value for all but one (press Enter to skip):")
# prompt for values by name
var_values = {}
for name in var_names:
value = input("Value of {}: ".format(name)).strip()
if value:
var_values[name] = sp.sympify(value)
# convert names to Sympy variable references
return {self.vars[name]:value for name,value in var_values.items()}
def solve(self):
values = self.prompt_for_values()
solutions = sp.solve(self.equality.subs(values))
# remove complex answers
solutions = [sol.evalf() for sol in solutions if sol.is_real]
return solutions
def __str__(self):
return str(self.equality)
# Define some equations!
equations = [
Equation("Time value of money (discrete)", "FV == PV * (1 + i) ** n"),
Equation("Time value of money (continuous)", "FV == PV * exp(i * n)" )
]
# Create menu
menu_lo = 1
menu_hi = len(equations) + 1
menu_prompt = "\n".join(
[""]
+ ["{}: {}".format(i, eq.label) for i, eq in enumerate(equations, 1)]
+ ["{}: Exit".format(menu_hi)]
+ ["? "]
)
def get_int(prompt, lo=None, hi=None):
while True:
try:
value = int(input(prompt))
if (lo is None or lo <= value) and (hi is None or value <= hi):
return value
except ValueError:
pass
def main():
while True:
choice = get_int(menu_prompt, menu_lo, menu_hi)
if choice == menu_hi:
print("Goodbye!")
break
else:
solutions = equations[choice - 1].solve()
num = len(solutions)
if num == 0:
print("No solutions found")
elif num == 1:
print("1 solution found: " + str(solutions[0]))
else:
print("{} solutions found:".format(num))
for sol in solutions:
print(sol)
if __name__ == "__main__":
main()

Categories