Athena Wiki

RSA Basics

cryptobeginner

Understand RSA key generation, encryption, decryption, and the math behind it for CTF crypto.

cryptorsapublic-keymodular-arithmeticprimeeulerchinese-remainder

RSA

RSA(Rivest-Shamir-Adleman) Algorithm is an asymmetric or public-key cryptography algorithm which means it works on two different keys: Public Key and Private Key. The Public Key is used for encryption and is known to everyone, while the Private Key is used for decryption and must be kept secret by the receiver.

How it works: Generate two large primes (p, q); modulus n = p × q; public exponent e (typically 65537); private exponent d computed using Euler's totient φ(n) = (p-1)(q-1); encryption uses C = M^e mod n; decryption uses M = C^d mod n.

Why it matters: RSA security relies entirely on factorization difficulty; small primes, shared factors, or improper padding create exploitable weaknesses; CTF challenges test prime factorization, Chinese Remainder Theorem, and Coppersmith's attack; most common asymmetric algorithm in real-world systems.

RSA
RSA key-generation overview

RSA Overview

RSA (Rivest–Shamir–Adleman) works on the principle that:

  • Public key (n, e) is known to everyone → encrypts
  • Private key d is secret → decrypts
  • Computing d from n and e is computationally hard (depends on factoring n)
ComponentWho knowsPurpose
n (modulus)PublicShared by all
e (public exponent)PublicEncryption
d (private exponent)SecretDecryption
p, q (primes)SecretOnly owner knows

Mathematical Foundations

Modular Arithmetic

ConceptDefinition
amodna \bmod nRemainder when aa is divided by nn (e.g. 17mod5=217 \bmod 5 = 2)
Modular inversea1modna^{-1} \bmod n: an integer xx with ax1(modn)ax \equiv 1 \pmod{n}; exists iff gcd(a,n)=1\gcd(a,n)=1

Euler's Totient Function

CaseFormula
Prime ppφ(p)=p1\varphi(p) = p-1
n=pqn = pq (distinct primes)φ(n)=(p1)(q1)\varphi(n) = (p-1)(q-1)

Carmichael's Lambda

For n=pqn = pq, λ(n)=lcm(p1,q1)\lambda(n) = \mathrm{lcm}(p-1,q-1). Some RSA implementations use λ\lambda instead of φ\varphi when computing dd.


RSA Algorithm

Key Generation

Choose two primes

Choose two large distinct prime numbers: p, q.

Compute modulus

Compute: n = p * q (this modulus is public).

Compute totient

Compute Euler's totient φ(n)=(p1)(q1)\varphi(n) = (p-1)(q-1) (or Carmichael λ(n)=lcm(p1,q1)\lambda(n) = \mathrm{lcm}(p-1,q-1)).

Choose public exponent

Choose ee with 1<e<φ(n)1 < e < \varphi(n) and gcd(e,φ(n))=1\gcd(e, \varphi(n)) = 1 (commonly e=65537=216+1e = 65537 = 2^{16}+1).

Compute private exponent

Compute de1(modφ(n))d \equiv e^{-1} \pmod{\varphi(n)}. This is the private exponent.

Distribute keys

Public key: (n, e) Private key: (n, d) or (p, q, d, e)

Encryption

cme(modn)c \equiv m^e \pmod{n}

Decryption

mcd(modn)m \equiv c^d \pmod{n}

This works because (me)dmedm(modn)(m^e)^d \equiv m^{ed} \equiv m \pmod{n} by Euler's theorem.


Python RSA from Scratch

Explanation: Generates a small RSA keypair, encrypts a short message, then decrypts it to demonstrate end-to-end RSA.

from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes, GCD
from math import lcm

# Key generation
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
phi = (p - 1) * (q - 1)

# Verify e and phi are coprime
assert GCD(e, phi) == 1

# Private exponent
d = pow(e, -1, phi)  # Python 3.8+ built-in modular inverse

# Encrypt
m = bytes_to_long(b"Hello CTF!")
c = pow(m, e, n)

# Decrypt
m_decrypted = pow(c, d, n)
print(long_to_bytes(m_decrypted))  # → b"Hello CTF!"

When You Have p and q

Explanation: Given the prime factors p and q, compute d and decrypt ciphertext c.

from Crypto.Util.number import long_to_bytes

p = ...
q = ...
e = 65537
c = ...

n = p * q
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

Common RSA Parameters in CTF

CTF challenges often give you some or all of:

GivenTypical next step
nn, ee, ccStandard scenario - look for small ee, factorable nn, or known attacks
pp, qq, ee, ccCompute φ\varphi and dd, then decrypt
nn, ee, dd, ccRecover factors from dd (see below)
Multiple moduligcd(n1,n2)\gcd(n_1, n_2) may reveal a shared prime

Factoring n Given d

If you know d (private exponent) and want p, q:

Explanation: Uses a randomized method to recover `p` and `q` from `n`, `e`, and `d` by exploiting the relation ed − 1 = k·φ(n).

import random
from math import gcd

def factor_with_d(n, e, d):
    """Recover p and q from n, e, d."""
    # ed - 1 = k * phi(n)
    k = e * d - 1

    while True:
        g = random.randint(2, n - 2)
        t = k

        while t % 2 == 0:
            t //= 2
            x = pow(g, t, n)
            if x > 1 and gcd(x - 1, n) > 1:
                p = gcd(x - 1, n)
                return p, n // p

p, q = factor_with_d(n, e, d)
print(f"p = {p}\nq = {q}")

Reading PEM Files

Loads RSA keys from PEM files and prints the key components (public n, e; private d, p, q).

from Crypto.PublicKey import RSA

# Load public key from PEM file
with open('public.pem', 'r') as f:
    pub = RSA.import_key(f.read())
    n = pub.n
    e = pub.e
    print(f"n = {n}")
    print(f"e = {e}")
    print(f"key size = {pub.size_in_bits()} bits")

# Load private key
with open('private.pem', 'r') as f:
    priv = RSA.import_key(f.read())
    d = priv.d
    p = priv.p
    q = priv.q

See also

  • ECC Basics - Elliptic Curve Cryptography overview and attacks.
  • Hash Functions - Hashing concepts used in signatures and protocols.
  • RSA Attacks - The full RSA attack catalogue (Wiener, Håstad, Coppersmith, common modulus, and more).

Last updated on

On this page