Search

RSA: The unbreakable code?

illustration

Overview

Secondary School

Mathematics, Computer Science

Quantum Computing

English

Overview

Keywords: encryption, decryption, modulo arithmetic, plaintext, ciphertext, modular exponentiation, cryptography
Age group: 16-18 years
Required knowledge/skills: basic understanding of Python
Time frame: 120 min (two lessons)

Author: Sam Robbins (UK)

Content

Lesson plan
Student exercises and teacher notes
Fermat’s Little Theorem
Programming issue
The RSA algorithm
Summary of process (table)
The RSA algorithm: summary
Breaking the RSA algorithm using a classical computer
Conclusion

Summary

This is the first of two lessons which aim to show how RSA encryption works and how quantum computers may, in the future, be able to break it. This lesson focusses solely on the RSA encryption system itself, showing students how the system works and the traditional approach to breaking the code.

Teaser Icon Quantum Algorithms

Lesson plan
 

Timing
in minutes
Lesson phasesActivityResources
0–15Exercise 1Introduction to Fermat’s Little Theorem + exercise to be done on pen and paper using a calculator.Worksheet,
calculator
15–35Exercise 2Teacher explains how to implement mod-ular exponentiation through repeated multiplication within modular arithmetic. Students implement the code listing shown and test with the numbers given in the exercise.Worksheet,
Python interpreter (an online editor should be sufficient)
35–45Exposition of the RSA system and an exampleTeacher explains how encryption and de-cryption work in RSA with reference to an example.Worksheet,
Python interpreter (an online editor should be sufficient)
45–75Exercise 3Students adapt code to encrypt and then decrypt a message using RSA.Worksheet,
Python interpreter (an online editor should be sufficient)
75–120Exercise 4Students write code to factorise the number given and time how long it takes.Worksheet,
Python interpreter (online editor may not be be sufficient for this exercise)

Student exercises and teacher notes

In this lesson, we will focus on the RSA encryption algorithm and classical methods to break it. The RSA algorithm was designed in 1977 by Rivest, Shamir and Adleman and remains one of the most successful forms of encryption to this day. If you have ever performed a financial transaction over the internet, it is likely that the security codes you used to do that will have been encrypted, and your identity verified, using the RSA system.

This lesson will look at the RSA methodology and show how, in the classical world, it is practically unbreakable.

Worksheet

The following tasks are available as worksheet for download as pdf and docx.

The tasks are also available as an interactive worksheet with embedded Python environment here.

Fermat’s Little Theorem

At the heart of the RSA system is a beautiful mathematical result known as Fermat’s Little Theorem:

x p1 1 ( mod p )

This states that any positive integer, x, when raised to the power of a prime number, p, minus one will give a remainder of one when the result is divided by p. The mod function here stands for modulo, which means “the remainder after division by” (in this case, p).

For example, take x=3 and p=5:

3 p1 = 34 = 81

81 / p = 81 / 5 = 16 remainder 1

Exercise 1

Check Fermat’s Little Theorem holds for the following values of x and p:

  1. x=2, p=3
  2. x=2, p=5
  3. x=4, p=5
  4. x=4, p=7
  5. x=5, p=11

Teacher should first model how modulo arithmetic works by showing the remainder of various numbers after division by another number. The answer to every part of this question is 1.

Programming issue

The final example in Exercise 1 hints at a potential problem in implementing the RSA system, namely that the power function grows very quickly. Even with very small prime numbers, we will quickly get overflow errors if we simply calculate the power function in full. However, we can avoid this problem by using the fact that raising a number to a power in modulo arithmetic is the same as raising the remainder to the same power.

For example, taking x=3 and p=5 again, we can see that:

34 = 92

But

9 4 ( mod 5 )

So rather than calculating 92 under the modulo operator, we can just calculate 42 and easily see that

42 = 16 1 ( mod 5 )

as expected.

We can therefore write a Python routine to calculate the power function in modulo arithmetic (also known as modular exponentiation), using a loop to multiply x by itself repeatedly but each time replacing the result with its remainder under division by p.

Exercise 2

Implement the following Python code (note that the % symbol implements the modulo function in Python):

def powerMod(a, b, c):  # raises a to the power of b modulo c
    res = a % c
    for i in range(0, b - 1):
        res = a * res % c
    return res

x = 5
p = 11

print(
    powerMod(x, p - 1, p)
)

Use the code to deduce which of the following are not prime numbers (because Fermat’s Little Theorem does not hold for them):

  1. 1367
  2. 1369
  3. 7527
  4. 7531
  5. 7537
  6. 15723
  7. 15727
  8. 18791

Teacher models how exponentiation can be performed by successive multiplication of a number by itself, each time replacing the result by its modulo equivalent (an example is provided on the worksheet that may be used).

Students then implement the code as written to test the numbers provided. The % symbol is the Python command for MOD. Students can use any value of x less than p for each of the questions. Using x=2 would be good enough for all questions. Any value of p for which the number returned by the function is not 1 is not a prime.

Answers: (b), (c), (d), (f) and (h) are not prime.

The RSA algorithm

Note

The next section goes through the mathematics of the RSA system, step by step. This section may be skipped, if the teacher prefers to focus on how the system works rather than why. The summary table at the bottom of this section provides all the information needed to implement the system.

RSA relies on a variant of Fermat’s Little Theorem that says the following:

x ( p1 ) ( q1 ) 1 ( mod pq )

where p and q are both primes.

For example, if x=2p=3 and q=5:

2 (p1) (q1) = 2 24 = 28 = 256

256 / pq = 256 / 15 = 17 remainder 1

Multiplying both sides of the identity by x gives:

x (p1) (q1) x x (mod pq)

x (p1) (q1) +1 x (mod pq)

This means that x raised to the power of (p1) (q1) +1 will return x (mod pq).

The RSA algorithm uses this fact to create a two-step process for first encrypting and then decrypting a message. If we can find two numbers e and d such that

ed 1 ( mod (p1) (q1) )

then

xed x (mod pq) .

We now define e to be our encryption key and d to be our decryption key and x to be the message we wish to encrypt.

Step 1 – encryption

We raise x to the power e to generate an encrypted message y.

xe y (mod pq)

The strength of the RSA system is built on the fact that knowledge of ye and pq is not sufficient to retrieve x. There is no way to find the e-th root in modulo arithmetic.

This can easily be seen from Fermat’s Little Theorem itself:

14 24 34 44 1 (mod 5)

So if we attempted to take the fourth root of 1 (mod 5) we would not be able to tell whether the original number was 1, 2, 3, or 4.

Step 2 – decryption

Once we have encrypted our message as y, the only way to decrypt the message is by raising to the power of d (mod pq). Using power rules, we can see that:

yd xe d xed x (mod pq)


The RSA algorithm: summary of process

 

SenderGeneral publicReceiver
What they know
x (message to be encrypted)
e (the encryption key)
pq (the modulus to be used)

They do not know p or q separately.
y (the encrypted message)
e (the encryption key)
pq (the modulus to be used)

They do not know p or q separately.
y (the encrypted message)
d (the decryption key)
pq (the modulus to be used)

They know p and q separately, which allows them to calculate d.
What they do
Calculate encrypted message
y = xe (mod pq)
Knowledge of e and pq is insufficient to be able to decrypt y.Calculate decrypted message
x = yd (mod pq)

Example

Choose p = 89, q = 151, pq = 13439. If we pick e = 7543, the corresponding decryption key is d = 7.

Choose a four-digit code to encrypt, e.g. 8571 and set up the code as follows:

def powerMod(a, b, c):  # raises a to the power of b modulo c
    res = a % c
    for i in range(0, b - 1):
        res = a * res % c
    return res

plainText = 8571
pq = 13439
e = 7543

encryptedMessage = powerMod(plainText, e, pq)
print(encryptedMessage)

This should return the encrypted value: 1134.

Now we can verify the system works by using the decryption key of 7 to decrypt the message as follows:

def powerMod(a, b, c):  # raises a to the power of b modulo c
    res = a % c
    for i in range(0, b - 1):
        res = a * res % c
    return res

cipherText = 1134
pq = 13439
d = 7

decryptedMessage = powerMod(cipherText, d, pq)
print(decryptedMessage)

This code now returns the decrypted message of 8571.

You can show the students that this example works:

7 7543 = 52801 and (p1) (q1) = 88 150 = 13200 , so

ed 1 ( mod (p1) (q1) ) as required.

It is possible to find a decryption key, d, such that

ed 1 ( mod (p1) (q1) )

whenever the highest common factor of e and (p1) (q1) is 1.

d is calculated by using the Extended Euclidean Algorithm (in the interests of time, showing how this works has been omitted from the lesson).

A student may wonder why an eavesdropper cannot work out d for themselves using this algorithm and hence break the code. The answer is that, even though they know the product pq, they do not know p or q individually and hence do not know

(p1) (q1) .

Being able to factorise pq is a computationally difficult problem and the heart of what makes RSA a very secure system.

Students should implement the example shown before going on to Exercise 3.

Exercise 3

Note

It is possible to automate the process of converting characters to numbers by using the ord() function, which returns the ASCII number for a given character. The chr() function does the inverse operation of turning a number into an ASCII character. Depending on students’ facility with Python, they may choose this approach or simply convert the characters into numbers manually before encrypting and decrypting. The listings below also employ arrays and loops to automate the process of encrypting and decrypting the whole message. Again, this is not essential for the learning objective and can be used or not, depending on students’ proficiency with Python.

Exercise 3a

Use pq=13439 and e = 5077 to encrypt the following message: QUANTUM.

Change each letter into a number and encrypt each in turn (assume A = 1, B = 2, C = 3, etc.)

Answers: [4114, 5656, 1, 7072, 249, 5656, 12523]

Example code listing:

def powerMod(a, b, c):  # raises a to the power of b modulo c
    res = a % c
    for i in range(0, b - 1):
        res = a * res % c
    return res

plainText = [
    "Q", "U", "A",
    "N", "T", "U",
    "M"
]

plainTextNumeric = []
for i in plainText:
    plainTextNumeric.append(ord(i) - 64)

pq = 13439
e = 5077

cipherTextNumeric = []
for i in plainTextNumeric:
    cipherTextNumeric.append(powerMod(i, e, pq))

print(cipherTextNumeric)

Exercise 3b

Use pq=13439 and d = 13 to decrypt your message.

Example code listing:

def powerMod(a, b, c):  # raises a to the power of b modulo c
    res = a % c
    for i in range(0, b - 1):
        res = a * res % c
    return res

cipherTextNumeric = [
    4114, 5656, 1,
    7072, 249,
    5656, 12523
]

pq = 13439
d = 13

plainTextNumeric = []
for i in cipherTextNumeric:
    plainTextNumeric.append(powerMod(i, d, pq))

print(plainTextNumeric)

plainText = []
for i in plainTextNumeric:
    plainText.append(chr(i + 64))

print(plainText)

The RSA algorithm: summary

The RSA system has two parts: a public key and a private key. The public key is comprised of e and pq. The private key is comprised of d and the separate numbers p and q.

The public key may be safely distributed in the knowledge that it may be used to encrypt messages, but not decrypt them. For example, a bank wishing to verify a transaction from a customer will publish its public key allowing the customer to encrypt some secret information (for example a PIN or the CVC number on a credit card).

The customer can then encrypt this information using

xe y ( mod pq )

knowing that if a hacker intercepts the encrypted message y, they will not be able to retrieve the secret information x even if they also have access to the encryption key e.

Only the bank, who holds the private key d, will be able to decrypt the message, checking the secret information and therefore being able to verify that the person making the transaction is who they say they are.

Breaking the RSA algorithm using a classical computer

To break RSA, we need to know d, but to work out d requires knowledge of

(p1) (q1) .

Although pq is part of the public key, it is not immediately obvious from this what

(p1) (q1)

is. In order to find it we must factorise pq, but if p and q are two large primes, factorising pq is a computationally difficult problem.

The following exercise illustrates the challenge:

Exercise 4

Write a program to factorise the number 900,239,055,271,631. Time how long it takes.

Depending on their facility with Python, the students may need some hints on how to do this. These might include:

  • Set up a loop which iterates through all numbers up to the square root of the number we are attempting to factorise;
  • Divide the target number by the loop counter. If we get a whole number, we have found a factor;
  • To test if the answer is a whole number, check if x / i is equal to x // i (i.e. if dividing x by i gives the same answer as integer division by i);
  • If this is the case, exit the loop and print out the result.

Answer: 900,239,055,271,631 = 30,003,209 × 30,004,759

Example code listing:

import time
import math

timeNow = time.time()
x = 900239055271631
i = 2
foundFactors = False

while foundFactors == False
and i < math.sqrt(x):
    i += 1
    if x / i == x // i:
        foundFactors = True

if foundFactors == True:
    print(i)
    print(int(x / i))

print(
    "Time taken = " +
    str(
        int(time.time() - timeNow)
    ) +
    " seconds"
)

   This listing uses the system clock to do the timings – this is not essential: the point of the exercise is simply to show that, even for these comparatively small numbers, it takes the computer a long time to work out factors. On the computer this program was written on, the runtime was 25 seconds!

Conclusion

Factoring is an example of an intractable problem in computing. We have a means of solving the problem (trial division), but as the numbers grow, the number of computations required grows too quickly for any computer to run in a reasonable time. This means it is possible to find a product of primes which no classical computer would ever be able to factorise, regardless of how much processing power it had. In this example, the two primes were 8 digits long. In a real-life implementation of RSA, the primes used would typically be 300 digits long each. Even the fastest supercomputers are unable to factorise numbers of this length in any time that could threaten the security of RSA encryption systems. For this reason, RSA remains a gold standard of internet security, on which many of the world’s online banking systems continue to depend.

However, quantum computing offers a method that could reduce the complexity of the factoring problem down to a speed that could make RSA breakable in real-time. In the next lesson, we will see how Shor’s Algorithm could threaten the security of the RSA method and how this potential threat is driving a revolution in cryptography.

Close search