simplersa/main.py

152 lines
3.8 KiB
Python
Raw Normal View History

2021-02-23 23:16:40 +00:00
#!/usr/bin/env python3
import math
import random
from itertools import combinations
def euclid(a, b):
2021-02-28 20:05:08 +00:00
"""returns the Greatest Common Divisor of a and b.
Inspired by https://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations"""
2021-02-23 23:16:40 +00:00
a = abs(a)
b = abs(b)
if a < b:
a, b = b, a
while b != 0:
a, b = b, a % b
return a
2021-02-28 20:05:08 +00:00
def coPrime(x, y):
2021-02-23 23:16:40 +00:00
"""returns 'True' if the values in the list L are all co-prime
otherwise, it returns 'False'. """
2021-02-28 20:05:08 +00:00
if euclid(x, y) != 1:
return False
2021-02-23 23:16:40 +00:00
return True
2021-02-28 20:05:08 +00:00
def iterative_extended_euclid(a, b):
""" returns the GCD (in old_r) of a and b as well as the "Bezout's Identity" such that
a*old_s + b*old_t = GCD(a,b).
Algorithm is adopted from https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode
"""
old_r, r = a, b
old_s, s = 1, 0
old_t, t = 0, 1
while r != 0:
quotient = old_r // r
old_r, r = r, old_r - (quotient * r)
old_s, s = s, old_s - (quotient * s)
old_t, t = t, old_t - (quotient * t)
print(old_r, old_s, old_t)
return old_r, old_s, old_t
2021-02-23 23:16:40 +00:00
def modInv(a, m):
"""returns the multiplicative inverse of a in modulo m as a
2021-02-28 20:05:08 +00:00
positive value between zero and m-1
Adopted from https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Extended_Euclidean_algorithm
"""
if coPrime(a, m):
linear_combination = iterative_extended_euclid(a, m)
print(linear_combination[1] % m)
return linear_combination[1] % m
2021-02-23 23:16:40 +00:00
else:
return 0
2021-02-28 20:05:08 +00:00
def miller_rabin(n, k):
2021-02-23 23:16:40 +00:00
2021-02-28 20:05:08 +00:00
# Implementation uses the Miller-Rabin Primality Test
# The optimal number of rounds for this test is 40
# See http://stackoverflow.com/questions/6325576/how-many-iterations-of-rabin-miller-should-i-use-for-cryptographic-safe-primes
# for justification
2021-02-23 23:16:40 +00:00
2021-02-28 20:05:08 +00:00
# If number is even, it's a composite number
2021-02-23 23:16:40 +00:00
if n == 2:
return True
if n % 2 == 0:
return False
2021-02-28 20:05:08 +00:00
r, s = 0, n - 1
while s % 2 == 0:
r += 1
s //= 2
for _ in range(k):
a = random.randrange(2, n - 1)
x = pow(a, s, n)
2021-02-23 23:16:40 +00:00
if x == 1 or x == n - 1:
2021-02-28 20:05:08 +00:00
continue
for _ in range(r - 1):
x = pow(x, 2, n)
if x == n - 1:
break
2021-02-23 23:16:40 +00:00
else:
return False
2021-02-28 20:05:08 +00:00
return True
2021-02-23 23:16:40 +00:00
def findAPrime(a, b, k):
"""Return a pseudo prime number roughly between a and b,
2021-02-28 20:05:08 +00:00
(could be larger than b). """
2021-02-23 23:16:40 +00:00
x = random.randint(a, b)
2021-02-28 20:05:08 +00:00
while True:
if miller_rabin(x, k):
2021-02-23 23:16:40 +00:00
return x
else:
x += 1
def newKey(a, b, k):
""" Try to find two large pseudo primes roughly between a and b.
2021-02-28 20:05:08 +00:00
Generate public and private keys for RSA encryption."""
p = findAPrime(a, b, k)
while True:
q = findAPrime(a, b, k)
if q != p:
break
2021-02-23 23:16:40 +00:00
n = p * q
2021-02-28 20:05:08 +00:00
m = (p - 1) * (q - 1) # Compute phi(n) for n=pq where p and q are prime
2021-02-23 23:16:40 +00:00
2021-02-28 20:05:08 +00:00
# Find and e that is coprime to phi(n) to be used in the public key
2021-02-23 23:16:40 +00:00
while True:
e = random.randint(1, m)
2021-02-28 20:05:08 +00:00
if coPrime(e, m):
2021-02-23 23:16:40 +00:00
break
2021-02-28 20:05:08 +00:00
# Let d be the modular inverse to e, to be used as private key
2021-02-23 23:16:40 +00:00
d = modInv(e, m)
return (n, e, d)
2021-02-28 20:05:08 +00:00
def encrypt(message, modN, e):
2021-02-23 23:16:40 +00:00
"""given a string message, public keys and blockSize, encrypt using
RSA algorithms."""
return pow(message, e, modN)
2021-02-28 20:05:08 +00:00
def decrypt(secret, modN, d):
2021-02-23 23:16:40 +00:00
"""reverse function of encrypt"""
return pow(secret, d, modN)
2021-02-28 20:05:08 +00:00
if __name__ == '__main__':
n, e, d = newKey(2**40, 2 ** 41, 20)
2021-02-23 23:16:40 +00:00
message = 35274764
print("original message is {}".format(message))
print("-"*80)
2021-02-28 20:05:08 +00:00
cipher = encrypt(message, n, e)
2021-02-23 23:16:40 +00:00
print("cipher text is {}".format(cipher))
print("-"*80)
2021-02-28 20:05:08 +00:00
deciphered = decrypt(cipher, n, d)
2021-02-23 23:16:40 +00:00
print("decrypted message is {}".format(deciphered))