# HITB 2015 Write-up - Crypto 300

## Introduction

The crypto 300 challenge was about RSA with a special generation of the prime numbers $p$ and $q$. We were given a mail mail.msg which has been encrypted with RSA and whose the public key is in the hitbctf.crt certificate.

## RSA’s Parameters Construction

The modulus $N$ is built by choosing randomly a first prime number $p$, the second prime number $q$ is constructed in the following way:

$$\alpha \cdot (p - 1) \equiv 1 \pmod{e}$$

$$q = (p\alpha \bmod e) + k\cdot e$$

$k$ is a positive integer such as $q$ is a prime number and $e$ is the public exponent which is also a random prime number.

The following code is the implementation in Python:

def gen_rsa_parameters():
r = os.urandom(63)
e = int(r.encode('hex'), 16)
e = next_prime(e)
r = os.urandom(64)
p = int(r.encode('hex'), 16)
p = next_prime(p)
q = (p*modinv(p-1, e)%e)
while not is_prime(q):
q += e
N = p*q
phi = (p-1)*(q-1)
d = modinv(e,phi)
return N,e,d,p,q


## Theoretical attack

Let’s $N^{\prime} = N \bmod{e}$. So we have

\begin{eqnarray} N^{\prime} & \equiv & p \cdot q \pmod{e} \\\ & \equiv & p \cdot ((p\alpha \bmod e) + k\cdot e) \pmod{e} \\\ & \equiv & p^2\alpha \pmod{e} \\\ \end{eqnarray}

We have $\alpha$ in the equation so we can introduce $p - 1$ to remove $\alpha$

\begin{eqnarray} N^{\prime} & \equiv & (p - 1 + 1)^2\alpha \pmod{e} \\\ & \equiv & (p - 1)^2\alpha + 2(p - 1)\alpha + \alpha \pmod{e} \\\ & \equiv & (p - 1) + 2 + \alpha \pmod{e} \\\ (p - 1)N^{\prime} & \equiv & (p - 1)^2 + 2(p - 1) + 1 \pmod{e} \end{eqnarray}

$$\boxed{(p - 1)^2 - (N^{\prime} - 2)(p - 1) + 1 \equiv 0 \pmod{e}}$$

Now we have a quadratic equation which only depends on $p$.

Let’s $X = p - 1$ and suppose that $N^{\prime} - 2$ is even and $N^{\prime} - 2 = 2b$.

\begin{eqnarray} X^2 - 2bX + 1 & \equiv & 0 & \pmod{e} \\\ (X - b)^2 - b^2 + 1 & \equiv & 0 & \pmod{e}\\\ (X - b)^2 & \equiv & b^2 - 1 & \pmod{e} \end{eqnarray}

by using quadratic residue we can find a solution. We can also use SAGE and the sqrt() function:

Np = N % e
b = (Np - 2) / 2
p = Mod(pow(b, 2) - 1, e).sqrt() + b + 1


At this point, we find $p \bmod{e}$ but not $p$ !

I tried to find $p$ by adding some $e$ but the distance between $p$ and $p \bmod{e}$ is huge. So I had to find another way.

By knowing $p \bmod{e}$ we can compute $\alpha$. Remember $$\alpha \cdot (p - 1) \equiv 1 \pmod{e}$$ and by having $\alpha$ and $p \bmod{e}$ we can brute force $q$ by adding $e$ until $(p\alpha \bmod e) + k\cdot e$ is prime and it divide $N$.

We did the assumption that $N^{\prime} - 2$ has to be even (so $N^{\prime}$ must be even) and in the certificate $N^{\prime}$ is even so everything is right.

## Pratical Attack

First we have to extract the modulus $N$ and the public key $e$ from the certificate:

$openssl x509 -in hitbctf.crt -text -noout Certificate: Data: Version: 1 (0x0) Serial Number: 18379438180976429416 (0xff10e1a5ac5a0968) Signature Algorithm: sha1WithRSAEncryption Issuer: C=NL, ST=Noord-Holland, L=Amsterdam, O=HITB, OU=CTF Validity Not Before: May 24 09:58:26 2015 GMT Not After : May 23 09:58:26 2016 GMT Subject: C=NL, ST=Noord-Holland, L=Amsterdam, O=HITB, OU=CTF Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:e6:eb:89:c1:8d:49:c9:a2:02:2b:e0:b4:65:14: 6e:0f:90:45:1e:a3:4c:6b:60:56:00:4e:bd:15:59: 55:b1:35:96:c2:d6:83:ad:2f:23:6b:0b:2c:0e:0b: 88:83:b5:d6:cb:8a:0b:4f:f9:b7:eb:64:8c:95:2b: 6b:ef:5a:6f:04:f5:64:17:f5:1c:a9:14:d9:ea:73: e7:dd:c5:f2:0d:ce:c3:9c:e8:4b:72:2a:0c:f3:d8: 5e:80:ce:78:64:63:e1:44:f6:1d:b5:9c:cf:45:ff: 0e:d3:7f:d0:ce:bd:37:a5:8d:8a:4b:08:33:9e:a3: 2c:bc:ab:61:64:03:fd:2c:c5 Exponent: 69:60:2d:93:8a:81:5f:14:cf:9f:b8:36:c2:e0:4d: 4d:De:82:ba:fc:8d:56:c2:6d:8c:89:ef:3c:40:69: 5d:d5:d4:ef:a7:36:36:43:15:14:95:f3:8c:bf:24: ae:94:30:92:40:79:12:00:1b:17:f5:53:33:9e:92: 70:70:49 Signature Algorithm: sha1WithRSAEncryption 17:2b:ea:be:90:ad:98:f2:2b:ff:f5:61:d3:ea:af:fb:35:3a: 67:10:91:13:db:60:55:d9:09:8b:c2:1a:cf:6b:c6:1f:f2:10: 7a:d1:7b:9d:ff:10:f2:f2:c0:a9:f5:aa:2e:09:93:40:88:92: 7d:98:ff:e1:cb:dc:db:35:8d:e0:4b:21:99:76:bf:db:04:a2: 62:a4:18:4e:fc:bb:a7:53:be:6a:a1:ef:ec:15:86:c1:f1:1e: 87:6a:e9:af:fe:d1:08:eb:de:22:28:c4:5e:be:f1:41:0a:ca: cf:cf:da:63:b1:c1:56:e8:0c:8e:56:7f:08:94:0d:2b:2a:08:  N = 1621575882314321757502664197090844942567381491984167028188381926885851 995558397927547394115469298694885747314992315746872071523931715177680193273 386465775883129725436206653605910592810579794603402792446164893148622893121 957048204358672599654432857497196823273138934901636721473789115585263150131 66594183212229 e = 21558488234539889837938770635971330903489839146766895224490179041465516 1931455822669631548838317075220811407344210520390992334648372016602816069805 30249 With SAGE: sage: Np = N % e sage: b = (Np - 2) / 2 sage: pp = int(Mod(pow(b, 2) - 1, e).sqrt()) + b + 1 sage: alpha = inverse_mod(int(X), int(e)) sage: q = (pp * alpha) % e sage: while not is_prime(q) and N % q != 0: ....: q += e sage: p = N / q sage: p 13317713478157317654574552532079837937895228108820477140030796245493222349714497856652987583926206280627498615972491072112647669795345566943409669535038641 sage: q 12176083266650126897170100375931110708350668494730113414987801764299563774952801449439933220072280766145748279998832962142839152786620322097065894585706069  We can now generate the private key by using rsatool: $ ./rsatools.py -o private.pem \
-e 21558488234539889837938770635971330903489839146766895224490179041465516193145582266963154883831707522081140734421052039099233464837201660281606980530249 \
-p 13317713478157317654574552532079837937895228108820477140030796245493222349714497856652987583926206280627498615972491072112647669795345566943409669535038641 \
-q 12176083266650126897170100375931110708350668494730113414987801764299563774952801449439933220072280766145748279998832962142839152786620322097065894585706069


Finally, we can decrypt the message:

openssl smime -decrypt -in mail.msg -inkey private.pem
hitb{0b21cc2025534dbd2965390d2bcef45d}


The sources are available here