from Crypto.Util.number import getPrime, long_to_bytes
from math import gcd # for greatest common divisor
class RSA:
def __init__(self):
# p, q (large prime numbers)
self.p = getPrime(512)
self.q = getPrime(512)
# calculate n (n is used for both the public key (n, e) and the private key (n, d))
self.n = p * q
# calculate t (totient, or called as 'phi')
self.t = (p - 1) * (q - 1)
# calculate e (e is one of the puclic key (n, e))
for i in range(2, self.t):
if gcd(i, self.t) == 1:
self.e = i
break
# calculate d (d is one of the private key(e, d))
self.d = pow(self.e, -1, self.t)
def encrypt(self, plaintext: str):
# ciphertext = plaintext ** e % n
ct = pow(int(plaintext.encode().hex(), 16), self.e, self.n)
return long_to_bytes(ct)
def decrypt(self, ciphertext: str):
# plaintext = ciphertext ** d % n
pt = pow(int(ciphertext.hex()), self.d, self.n)
return long_to_bytes(pt)
def sign(self, plaintext: str):
h = SHA256.new()
h.update(plaintext.encode())
# signed_plaintext = hash(plaintext) ** d % n
signed_pt = pow(bytes_to_long(h.digest()), self.d, self.n)
return signed_pt
msg = "Hello"
rsa = RSA()
enc_msg = rsa.encrypt(msg)
dec_msg = rsa.decrypt(enc_msg)
Basic Rules
n
p and q should be prime numbers.
n = p * q
Totient (Phi)
t = (p - 1) * (q - 1)
e (Exponentiation)
65536 is often used for the value of exponentiation (e).
e = 65537
Decryption Key
d = e ** -1 % t
Encrypt/Decrypt
# Encrypt
ciphertext = plaintext ** e % n
# Decrypt
plaintext = ciphertext ** d % n