Powered by AppSignal & Oban Pro

RSA step by step

notebooks/rsa_step_by_step.livemd

RSA step by step

1. What RSA is doing

RSA uses a pair of mathematically related keys:

  • πŸ”“ Public key β€” can be shared with everyone.
  • πŸ” Private key β€” must remain secret.

For encryption, the important idea is:

              Alice                                  Bob
       wants to send "7"                       owns the key pair

                                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                    β”‚ PUBLIC KEY  β”‚
                                                    β”‚   (n, e)    β”‚
                                                    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                                           β”‚
                         public key β—€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚ message β”‚
                         β”‚    7    β”‚
                         β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                              β”‚
                              β”‚ use public key
                              β”‚
                              β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚     ENCRYPT       β”‚
                    β”‚                   β”‚
                    β”‚   c = m^e mod n   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚ciphertextβ”‚
                         β”‚    13    β”‚
                         β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β”‚ send over network
                              β”‚
              ────────────────┼──────────────────────────────▢
                              β”‚
                                                          Bob
                                                           β”‚
                                                           β–Ό
                                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                    β”‚ PRIVATE KEY β”‚
                                                    β”‚   (n, d)    β”‚
                                                    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                                           β”‚
                                                           β–Ό
                                                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                 β”‚      DECRYPT      β”‚
                                                 β”‚                   β”‚
                                                 β”‚   m = c^d mod n   β”‚
                                                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                           β”‚
                                                           β–Ό
                                                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                      β”‚ message β”‚
                                                      β”‚    7    β”‚
                                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The interesting property is:

                    PUBLIC                         PRIVATE

message ──────▢ RSA operation ──────▢ ciphertext ──────▢ RSA operation
   7               using e                13               using d
                                                               β”‚
                                                               β–Ό
                                                               7

The public key can therefore be given to anyone:

Public key
   β”‚
   β”œβ”€β”€ n
   └── e

while the private key stays with the owner:

Private key
   β”‚
   β”œβ”€β”€ n
   └── d

For now, we will ignore how the keys were generated.

Assume somebody has already given us:

public_key = {55, 3}
private_key = {55, 27}

That means:

Public key
(n, e)
(55, 3)


Private key
(n, d)
(55, 27)

Let's encrypt the number 7.

message = 7

{n, e} = public_key

ciphertext =
  message
  |> Integer.pow(e)
  |> rem(n)

ciphertext

Result:

13

So this happened:

        message
           7
           β”‚
           β”‚ public key (55, 3)
           β–Ό
      7Β³ mod 55
           β”‚
           β–Ό
          13
       ciphertext

Now decrypt it with the private key:

{n, d} = private_key

decrypted_message =
  ciphertext
  |> Integer.pow(d)
  |> rem(n)

decrypted_message

Result:

7

So the complete journey was:

                    PUBLIC KEY                     PRIVATE KEY
                     (55, 3)                        (55, 27)
                        β”‚                               β”‚
                        β–Ό                               β–Ό

      7  ─────────▢  7Β³ mod 55  ─────▢  13  ─────▢ 13²⁷ mod 55 ─────▢ 7

   message                            ciphertext                       message

Or mathematically:

Encryption:

c = m^e mod n

c = 7Β³ mod 55
c = 13

and:

Decryption:

m = c^d mod n

m = 13²⁷ mod 55
m = 7

Why does this work?

7
β”‚
β”‚ raise to e
β–Ό
7^e mod n
β”‚
β”‚ raise to d
β–Ό
7 again

And where did these numbers come from?

n = 55
e = 3
d = 27

That is what we will build step by step.

The journey starts with two prime numbers:

              p = 5              q = 11
                 \                /
                  \              /
                   \            /
                    β–Ό          β–Ό

                      n = p Γ— q

                      n = 55

From p and q, we will eventually construct:

             p                  q
              \                /
               \              /
                β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                       β”‚
                       β–Ό
                       n
                       β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
                β”‚             β”‚
                β–Ό             β–Ό
                e             d
                β”‚             β”‚
                β–Ό             β–Ό
          PUBLIC KEY     PRIVATE KEY
            (n, e)         (n, d)

Important: this notebook is implementing RSA with tiny numbers to understand the mathematics. It is not an implementation that should be used for real cryptography.

Main Parts

Key generation

                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚ KEY GENERATIONβ”‚
                 β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                   β”‚
              β–Ό                   β–Ό
         secret p             secret q
              β”‚                   β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
                   n = p Γ— q
                        β”‚
                        β–Ό
                 derive e and d
                        β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                   β”‚
              β–Ό                   β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚  PUBLIC KEY  β”‚     β”‚ PRIVATE KEY  β”‚
       β”‚    (n, e)    β”‚     β”‚    (n, d)    β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Encryption and decryption

       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚   MESSAGE   β”‚
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
              β”‚
              β–Ό
     convert / pad message
              β”‚
              β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚ PUBLIC KEY  β”‚
       β”‚    (n, e)   β”‚
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
              β”‚
              β”‚  c = m^e mod n
              β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚ CIPHERTEXT  β”‚
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
              β”‚
              β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚ PRIVATE KEY β”‚
       β”‚    (n, d)   β”‚
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
              β”‚
              β”‚  m = c^d mod n
              β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚   MESSAGE   β”‚
       β”‚  recovered  β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Section

What is a prime number?

# A prime number has exactly two positive divisors: 1 and itself
prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23]
# 11 = 1x11 -> prime, because it is only divisible by 1 and itself
# 12 = 2 Γ— 6 = 3 Γ— 4 -> not a prime, because it is divisible by 1, 2, 3, 4, 6, itself

RSA chooses two primes

# Requirements for the prime numbers:
# 1. They must be different p != q
# 2. They must be big (e.g. ~1024 bits each or ~300 decimal digits). NOTE: 2^1024 ~ 10^308
# 3. They must be secret
p = 11 # secret
q = 17 # secret

RSA multiplies them

# The product of these two primes is ~2048 bits number or ~600 decimal digits
# RSA reveals the product while hiding its factors.
n = p * q # public
# NOTE: If the numbers are not big you can easily find them 
# Is n divisible by 2? -> no.
# Is n divisible by 3? -> no.
# Is n divisible by 5? -> no.
# Is n divisible by 7? -> no.
# Is n divisible by 11? -> yes. Thus p = 11 and q = n / p = 187 / 11 = 17.

# Why different p and q?
# Let's pick p and q to be equal to 4957
# p1 = 4957
# n1 = p1 * p1
# :math.sqrt(n1)
# Then only thing we need to do is to take the square root of n and we will find p.

# What is the role of n?
# 1. It is the modulus used by RSA arithmetic.
# 2. It hides p and q behind the difficult integer-factorisation problem.

Why primes rather than arbitrary numbers?

# This is partly because prime numbers give RSA very clean mathematical structure.
# Prime numbers allows us to use #Euler's totient function β€” Ο†(n). https://en.wikipedia.org/wiki/Euler%27s_totient_function
# Ο†(n) tells us: How many positive integers smaller than n are coprime with n?

What does coprime mean?

# Two numbers are coprime if their greatest common divisor is 1.
a = 8 # divisors 1, 2, 4, 8
b = 15 # divisors 1, 3, 5, 15
# a and b are coprime because the only factor they share is 1.
Integer.gcd(8, 15) # greatest common divisor
# Integer.gcd(6, 15) # 6 -> 1, 2, 3, 6
# NOTE: the coprimes don't need to be prime themselves

What does Ο†(n) actually count?

# take n = 10
# Ο†(n) looks at
# 1 2 3 4 5 6 7 8 9
# Checks if they are coprime
# 1 β†’ gcd(1,10) = 1    βœ“
# 2 β†’ 2                βœ—
# 3 β†’ 1                βœ“
# 4 β†’ 2                βœ—
# 5 β†’ 5                βœ—
# 6 β†’ 2                βœ—
# 7 β†’ 1                βœ“
# 8 β†’ 2                βœ—
# 9 β†’ 1                βœ“
# Integer.gcd(5, 10)
# So the coprimes are 1, 3, 7, 9. There are four.
# Therefore Ο†(10) = 4

Ο†(p) is especially simple when p is prime

# Suppose p = 7; a prime number
# Every positive number smaller than 7 is coprime with 7:
# 1, 2, 3, 4, 5, 6
# This is because the prime number has as a divisor only 1 and itself.
# So none of the numbers 1..6 can share a divisor with it other than 1.
# Ο†(7) = 6
# More generally when p is prime Ο†(p) = p - 1. 
# This fact is one reason primes are so convenient in RSA.

Now return to our RSA example

p = 11
q = 17
n = p * q # 187 = 11x17

# What is Ο†(187)?
# 187 = 11x17
# A number fails to be coprime with 187 only if it is divisible by:
# 11 or 17
# Let's look at multiples of 11
# The only numbers in the range 1..186 that are divisible by 11 are
# 11
# 22
# 33
# 4x11
# ...
# 15x11 = 165
# 16x11 = 176
# 17x11 = 187 this is bigger than 186 thus we stop at 16.
# So we eliminate 16 numbers.

# Let's now look at multiples of 17
# 17
# 34
# 3x17
# ...
# 10x17 = 170
# 11x17 = 187 this is bigger than 186 thus we stop at 10.
# So we eliminate 10 numbers.

# We count what remains 186 - 16 - 10 = 160
# Therefore Ο†(187) = 160

Where does the famous RSA formula come from?

# Let's start with n = p * q
# Among the numbers 1...p*q, there are:
# q multiples of p:
#    p, 2p, 3p, …, q*p
# and p multiples of q:
#    q, 2q, 3q, …, p*q
# But p * q appears in both lists, so we've counted it twice.
# Therefore the number divisible by p or q is:
#    p + q βˆ’ 1
# There are p*q numbers total, so the number coprime to p*q is:
#    p * q βˆ’ (p + q βˆ’ 1)
# Expand: 
#    p * q - p - q + 1
# Factor:
#    (p - 1) * (q - 1)
#
# Ο†(n) = Ο†(p*q) = (p - 1) * (q - 1) 
# Ο†(187) = Ο†(11*17) = (11 - 1) * (17 - 1) = 10 * 16 = 160
# NOTE: This works only if the p and q are prime

But why does RSA care about this count?

# When working modulo n, the numbers coprime with n have a special property:
# They have multiplicative inverses modulo n.

What does a modulo n mean?

# Modulo n means we only care about the remainder after division by n.
# For example, modulo 10:
# 27 / 10 = 2 remainder 7
# 27 mod 10 = 7
# 7 mod 10 = 7
# This means 27 and 7 are equivalent when working modulo 10.
Integer.mod(27, 10) == Integer.mod(7, 10)

# The numbers therefore "wrap around" every 10:
# 7
# 17
# 27
# 37
# 47
# ...
# all are 7 modulo 10
Enum.map([7, 17, 27, 37, 47, 57], &Integer.mod(&1, 10)) 
|> IO.inspect(charlists: :as_lists)

# You can think of modular arithmetic a little like a clock:

# modulo 10
# 0 β†’ 1 β†’ 2 β†’ 3 β†’ ... β†’ 9
# ↑                       β”‚
# β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

# After reaching 9, adding 1 takes us back to 0.

# For RSA, this "wrapping around" is important 
# because almost all of the core calculations happen modulo some number.

What does a multiplicative inverse modulo n mean?

# Normally, a multiplicative inverse is a number that gets us back to 1.
# For example the inverse of 5 is 1/5.
# 5 * 1/5 = 1.

# In modular arithmetic we ask a slightly different question:

# For a number a, can we find another integer x such that their product becomes 1
# after taking modulo n?

# Mathematically:
#    a Γ— x ≑ 1 (mod n)

# For example let's work modulo 10.
# Let's take a = 3
# The multiplicative inverse of 3 modulo 10 is 7:
# 3 Γ— 7 = 21
# 21 mod 10 = 1
Integer.mod(3 * 7, 10)

# But not every number has an inverse.

# For example, 2 has no multiplicative inverse modulo 10.

# The reason is:
# gcd(2, 10) = 2 
Integer.gcd(2, 10)

# They are not coprime!
# A modular inverse exists exactly when:
# gcd(a, n) = 1 
# a and n need to be coprime

Why does RSA care?

# Earlier we calculated:
# n = 187 
# Ο†(187) = 160
# RSA needs to choose a public exponent `e` that is coprime with 160.

# For example:
# e = 7
# gcd(7, 160) = 1
Integer.gcd(7, 160)
# Therefore 7 has a multiplicative inverse modulo 160.
# That inverse is:
# d = 23
# because:
# 7 Γ— 23 = 161
# 161 mod 160 = 1
Integer.gcd(23, 160)
defmodule RsaLab.Math do
  # Euler's totient (phi) for n = p * q, where p and q are distinct primes.
  def phi_from_primes(p, q) do
    (p - 1) * (q - 1)
  end
end

p = 11
q = 17

n = p * q
phi = RsaLab.Math.phi_from_primes(p, q)

%{
  p: p,
  q: q,
  n: n,
  phi: phi
}

1 and itself