CryptoBook
  • CryptoBook
  • Book Plan
  • Style Guide
    • Sample Page
  • Contributors
  • Fundamentals
    • Mathematical Notation
    • Division and Greatest common divisor
      • Euclidean Algorithm
    • Modular Arithmetic
      • Theorems of Wilson, Euler, and Fermat
        • Fermat's Little Theorem in Detail
        • Euler's Theorem in Detail
      • Quadratic Residues
    • Continued Fractions
  • Number Theory
  • Ideals
  • Polynomials With Shared Roots
  • Integer Factorization
    • Pollard rho
    • Sieves
  • Abstract algebra
    • Groups
      • Another take on groups
      • Discrete Log Problem
    • Rings
    • Fields
    • Polynomials
  • Elliptic Curves
    • Untitled
  • Lattices
    • Introduction
    • LLL reduction
      • Gram-Schmidt Orthogonalization
      • Lagrange's algorithm
      • LLL reduction
    • Lattice reduction
      • Minkowski reduced
      • HKZ reduced
      • LLL reduced
    • Applications
      • Coppersmith algorithm
      • Extensions of Coppersmith algorithm
    • Hard lattice problems
    • Lattices of interest
    • Cryptographic lattice problems
      • Short integer solutions (SIS)
      • Learning with errors (LWE)
      • Ring-LWE
      • NTRU
    • Interactive fun
    • Resources and notations
  • Asymmetric Cryptography
  • RSA
    • Proof of correctness
    • RSA application
    • Low Private Component Attacks
      • Wiener's Attack
      • Boneh-Durfee Attack
    • Common Modulus Attack
    • Recovering the Modulus
  • Diffie-Hellman
    • MITM
  • Elliptic Curve Cryptography
  • Symmetric Cryptography
    • Encryption
    • The One Time Pad
    • AES
      • Rijndael Finite Field
      • Round Transformations
  • Hashes
    • Introduction / overview
    • The Birthday paradox / attack
  • Isogeny Based Cryptography
    • Introduction to Isogeny Cryptography
    • Isogenies
    • Isogeny and Ramanujan Graphs
  • Appendices
    • Sets and Functions
    • Probability Theory
Powered by GitBook
On this page
  • Scenario
  • What we know
  • Process
  • Practical Notes
  • Code Example

Was this helpful?

Export as PDF
  1. RSA

Recovering the Modulus

When you want to recover N given some (plaintext, ciphertext) pairings

PreviousCommon Modulus AttackNextDiffie-Hellman

Last updated 4 years ago

Was this helpful?

Scenario

Consider the case that that you know a set of (plaintext, ciphertext) pairings - this may be that you are provided them, or that you have access to some functionality that returns ciphertexts for provided plaintexts. If you do not know the modulus, but know the exponent used (note: this may be prone to a brute-force regardless), then given these pairings you can recover the modulus used.

What we know

Let the following be known:

  • plaintext && ciphertext pairings:

(Mi,Ci) for i∈[1,∞](M_i,C_i) \text{ for } i \in [1,\infty] (Mi​,Ci​) for i∈[1,∞]
  • public exponent e (e.g. e = 65537 = 0x10001)

Process

The idea behind this attack is effectively finding common factors between pairings. Recall that, under general RSA encryption, we have:

C=Me (mod N)C = M^{e} \text{ } (mod\text{ }N)C=Me (mod N)

and recall what modular arithmetic tells us about the relation between these terms, namely that:

This, rearranged, tells us that

However, this is only true for the case that

Thus:

Practical Notes

  • In reality, you're likely to only need two or three (plaintext, ciphertext) pairings (in the context of ctf challenges and exercises), and as such computations can be manual if needed, but shouldn't be too complex

  • As it's likely you'll be dealing with large numbers, overflows and precision errors may arise in code - using libraries like gmpy provide support for integers of (theoretically) infinite size, and some nice accompanying features too (like in-built gcd and efficient modular exponentiation)

  • These two statements are mathematically equivalent, but one is easier to implement in code:

Code Example

import gmpy2

"""
@param pairings
    list: [(pt1, ct1), (pt2, ct2), ..., (ptk, ctk)]
@param e
    int : encryption exponent
@return
    int : recovered N
"""
def recover_n(pairings, e):
    pt1, ct1 = pairings[0]
    N = ct1 - pow(pt1, e)
    
    # loop through and find common divisors
    for pt,ct in pairings:
        val = gmpy2.mpz(ct - pow(pt, e))
        N = gmpy2.gcd(val, N)
    
    return N
    
a≡b (mod N)a=b+kN for some k∈Za \equiv b\text{ }(mod\text{ } N)\\ a = b + kN \text{ for some } k \in \mathbb{Z} a≡b (mod N)a=b+kN for some k∈Z
a−b≡0 (mod N)a−b=kNa - b \equiv 0\text{ } (mod \text{ } N)\\ a - b = kNa−b≡0 (mod N)a−b=kN

What this means for our known pairings is that, given we know m,cm, cm,c and eee, we can form the relationship:

Ci−Mie≡0 (mod N)Ci−Mie=kiNC_i - M_i^e \equiv 0\text{ } (mod \text{ } N)\\ C_i - M_i^e = k_iNCi​−Mie​≡0 (mod N)Ci​−Mie​=ki​N

Thus we can calculate for the value kNkNkN, though don't know either value individually - we want to somehow derive NNN.

Observe that any two pairings will equate to such a value, both with NNN as a factor. We can take the gcd of these two values, and it is probable that the resulting value will be our NNN value, such that:

N=gcd(C1−M1e,C2−M2e)N = gcd(C_1 - M_1^e, C_2 - M_2^e)N=gcd(C1​−M1e​,C2​−M2e​)
gcd(k1,k2)=1gcd(k_1, k_2) = 1gcd(k1​,k2​)=1

i.e., both k1k_1k1​and k2k_2k2​are coprime. In the case that they are not, i.e. gcd(k1,k2)≠1gcd(k_1, k_2) \ne 1gcd(k1​,k2​)=1, we have that

aN=gcd(C1−M1e,C2−M2e) s.t. 1≠a∈ZaN = gcd(C_1 - M_1^e, C_2 - M_2^e) \text{ s.t. } 1 \ne a \in \mathbb{Z}aN=gcd(C1​−M1e​,C2​−M2e​) s.t. 1=a∈Z

In such a case, we don't have sufficient information to completely recover the modulus, and require more plaintext-ciphertext pairs to be successful. In general, the more pairings you have, the more confident you can be the value you calculate is NNN. More specifically:

Pr(a≠1)→0 as k→∞Pr(a \ne1) \rightarrow 0 \text{ as } k\rightarrow \inftyPr(a=1)→0 as k→∞
N=lim⁡k→∞gcd(C1−M1e,C2−M2e,...,Ck−Mke)N = \lim_{k \rightarrow \infty} gcd(C_1 - M_1^e, C_2 - M_2^e, ..., C_k - M_k^e)N=k→∞lim​gcd(C1​−M1e​,C2​−M2e​,...,Ck​−Mke​)
gcd(a,b,c,d,...)=gcd(a,gcd(b,gcd(c,gcd(d,...))))gcd(a, b, c, d, ...) = gcd(a, gcd(b, gcd(c, gcd(d, ...))))gcd(a,b,c,d,...)=gcd(a,gcd(b,gcd(c,gcd(d,...))))