RSA (Rivest Shamir Adleman)

Last modified: 2024-03-08

Cryptography

RSA is a public-key cryptosystem that is widely used for secure data transmission.

RSA Algorithm in Python

Reference: https://medium.com/@gowtham180502/implementing-rsa-algorithm-using-python-836f7da2a8e0

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 = self.p * self.q

		# calculate t (totient, or called as 'phi')
		self.t = (self.p - 1) * (self.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

Interesting Rules

Factoring n into two prime numbers (p, q)

Reference: https://cryptohack.org/courses/public-key/rsa_factoring/

We can calculate prime numbers (p and q) by factoring n (n = p * q).
To do that, we can use online tools such as factordb, or create a Python script as below.

from sympy import factorint

n = 510143758735509025530880200653196460532653147

factors = factorint(n)
print(f"factors: {factors}")
# factors: {25889363174021185185929: 1, 19704762736204164635843: 1}

Phi is n - 1 if n is prime

If n is prime, totient (phi) will be n - 1.

t = n - 1

Calculate Totient from Many Factors

If there are many factors of n, we can multiply each (factor - 1) to calculate totient.

factors = [factor1, factor2, factor3, factor4]

t = 1
for factor in factors:
    t *= (factor-1)

print(f"totient: {t}")

Using CLI

Decrypt

openssl pkeyutl -decrypt -in ciphertext -inkey private-key.pem

Encrypt

openssl pkeyutl -encrypt -in plain.txt -inkey public-key.pem -pubin

Generate a Keypair

To generate a private key,

# genrsa: Generate an RSA private key
openssl genrsa -out private-key.pem 2048

To generate a public key,

openssl rsa -in private-key.pem -pubout -out public-key.pem

Get the Prime Number

openssl rsa -in private-key.pem -text -noout

Diffie-Hellman Exchange

openssl dhparam -out dhparams.pem 2048