Fractional RSA

COMP2633 Week 8 Homework B

12. Preface

Challenge authored by Tom Yueng, Firebird Core member.

14 solves. First blood in 24 minutes.

13. Analysis

The challenge implements a variation of RSA, so called β€œFractional RSA”. Normally the setup for RSA uses:

However, in this challenge:

Furthermore, the modulus 𝑛 is hidden, and we are only allowed 20 queries.

14. The Vulnerability

RSA depends on 𝑛 being difficult to factor, thus it is difficult to compute πœ‘(𝑛) and you cannot determine 𝑑≑𝑒modπœ‘(𝑛) for decryption.

However, if we have all the 10 factors,

𝑛=π‘Žβ‹…π‘β‹…π‘β‹…π‘‘β‹…π‘’β‹…π‘“β‹…π‘”β‹…β„Žβ‹…π‘–β‹…π‘—

Then we know that,

πœ‘(𝑛)=(π‘Žβˆ’1)(π‘βˆ’1)(π‘βˆ’1)(π‘‘βˆ’1)(π‘’βˆ’1)(π‘“βˆ’1)(π‘”βˆ’1)(β„Žβˆ’1)(π‘–βˆ’1)(π‘—βˆ’1)

Since the servers oracle allows us to compute the square root of integers mod𝑛, we can exploit this to factor 𝑛.

15. The Attack Vector

15.1. Step 1: Recover N

The encryption oracle computes π‘β‰‘π‘š2mod𝑛, so for large random π‘š:

π‘š2βˆ’π‘=π‘˜β‹…π‘›

Thus we can compute π‘Ž=π‘š2βˆ’π‘ for several random π‘š.

Then take the gcd(π‘Ž1,π‘Ž2,…,π‘Žπ‘˜) to recover 𝑛.

This is because π‘˜β‹…π‘› will likely be different for each π‘š.

If gcd(π‘˜1,π‘˜2,…,π‘˜π‘˜)=1, then gcd(π‘Ž1,π‘Ž2,…,π‘Žπ‘˜)=𝑛.

15.2. Step 2: Factoring N

Now that we have 𝑛, we can use the decryption oracle to factor it.

It may not seem obvious that we need to do this, however if you look at how the decryption oracle works

def sqrt_mod_n(a, ps):
    residues = []
    for p in ps:
        q = nthroot_mod(a, 2, p)
        if q is None:
            return -1
        else:
            residues.append(q)
    return int(crt(ps, residues)[0])

𝑝𝑠 is the list of prime factors of 𝑛. Thus, the decryption oracle is actually computing the square root mod each prime factor of 𝑛 and then combining them using the Chinese Remainder Theorem.

This gives the hint that we can use the square root oracle to factor n.

To factor 𝑛, we will start with the following approach:

Why query the oracle for decryption?

Encryption with 𝑒=12 means 𝑐=π‘šmod𝑛.

So instead when we input 𝑐, then π‘β‰‘π‘šmod𝑛.

Let 𝑦=π‘š, then we know that 𝑦2≑𝑐≑π‘₯2mod𝑛. And further,

𝑦2≑π‘₯2mod𝑛𝑦2β‹…π‘₯βˆ’2≑1mod𝑛(𝑦⋅π‘₯βˆ’1)2≑1mod𝑛

Let 𝑠=𝑦⋅π‘₯βˆ’1, then

𝑠2≑1mod𝑛𝑠2βˆ’1≑0mod𝑛(π‘ βˆ’1)(𝑠+1)≑0mod𝑛

Now we have two factors of 𝑛, we can further make use GCD to determine the prime factors,

gcd(𝑠+1,𝑛)andgcd(π‘ βˆ’1,𝑛)

This is because for each prime 𝑝𝑖|𝑛, since 𝑠2mod𝑝𝑖≑1, 𝑠mod𝑝𝑖 is either Β±1.

So, gcd(𝑠+1,𝑛) will be the product of all 𝑝𝑖|(π‘ βˆ’1), while gcd(π‘ βˆ’1,𝑛) will be the product of all 𝑝𝑖|(𝑠+1).

Since we can split 𝑛 into two composite factors, by repeating this process we but instead taking the gcd against the composite factors of n, we can factorize 𝑛 into its 10 prime factors.

In the ideal case, we would need log2(10)β‰ˆ4 queries to fully factor 𝑛. So accounting for randomness we can expect to factor 𝑛 within 8-12 queries.

15.2.1. The Edge Case

You may notice that if 𝑠2=1, i.e. π‘₯2≑𝑦2mod𝑛 then this won’t work.

This doesn’t matter much as we can prove that it is quite rare that π‘₯2≑𝑦2mod𝑛 by looking at the code of the square root oracle.

Since the square root oracle takes the square root of our input modulo each prime factor.

For each prime factor 𝑝𝑖, π‘Ž2 would have two roots Β±π‘Žmod𝑝.

When we combine these via CRT, there are 210=1024 possiblities of 𝑦2mod𝑛

So there is a 11024β‰ˆ0.1% chance that 𝑦2≑π‘₯2mod𝑛

16. Decrypting the flag

As we said earlier, πœ‘(𝑛)=(𝑝1βˆ’1)(𝑝2βˆ’1)…(𝑝10βˆ’1).

We just need to compute π‘‘β‰‘π‘’βˆ’1modπœ‘(𝑛).

Then we can trivially decrypt the flag with

π‘š=𝑐𝑑mod𝑛