First of all, this is a challenge from HTB: LostKey under Crypto category and weighed as “Medium”. But man, this is a total brain rot to me.

Second, since I don’t know what the f am I doing, I just ended up reading walkthrough, even just reading, I can’t still comprehend what’s happening.**Lastly, the solution below is a complete copypasta from here. FULL CREDITS TO THEM.**

## The challenge

The challenge contains 2 files

```
#!/usr/bin/env python3
from Crypto.Util.number import *
from hashlib import sha1
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from secret import flag, n
class coord:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"coord({self.x}, {self.y})"
class EC:
def __init__(self, p):
self.p = p
self.zero = coord(0,0)
def add(self, P,Q):
if P == self.zero:
return Q
if Q == self.zero:
return P
if P.x == Q.x and P.y == -Q.y:
return self.zero
if P != Q:
Lambda = (Q.y - P.y) * inverse(Q.x - P.x, self.p)
else:
Lambda = (3*(P.x*Q.x) + 417826948860567519876089769167830531934*P.x + 177776968102066079765540960971192211603) * inverse(P.y+Q.y+3045783791, self.p)
Lambda %= self.p
R = coord(0,0)
R.x = (Lambda**2-P.x-Q.x-208913474430283759938044884583915265967) % self.p
R.y = (Lambda*(P.x-R.x) - P.y - 3045783791) % self.p
return R
def mul(self, P, n):
Q = P
R = self.zero
while n > 0:
if n % 2 == 1:
R = self.add(R,Q)
n >>= 1
Q = self.add(Q,Q)
return R
def encrypt(key):
iv = __import__('os').urandom(16)
key = sha1(str(key).encode('ascii')).digest()[0:16]
cipher = AES.new(key, AES.MODE_CBC, iv)
ct = cipher.encrypt(pad(flag,16))
return(ct.hex(),iv.hex())
assert(n < 38685626227668133590597631)
e = EC(101177610013690114367644862496650410682060315507552683976670417670408764432851)
G = coord(14374457579818477622328740718059855487576640954098578940171165283141210916477, 97329024367170116249091206808639646539802948165666798870051500045258465236698)
print ("G =",G)
print ("Gn =", e.mul(G,n).x)
enc = encrypt(n)
print ("Ciphertext: {}\nIV: {}".format(enc[0],enc[1]))
```

`encrypt.py`

The class in `EC`

defines an elliptic curve. The encryption process is to use a point on the curve `G`

to `n * G`

calculate `Gn`

and use it as the AES key to encrypt the plaintext, so the value `n`

required to decrypt the ciphertext is obtained .`n`

`output.txt`

The text file gives the values of `G`

, `Gn`

(x coordinates), `Ciphertext`

and `IV`

`G = coord(14374457579818477622328740718059855487576640954098578940171165283141210916477, 97329024367170116249091206808639646539802948165666798870051500045258465236698)`

Gn = 32293793010624418281951109498609822259728115103695057808533313831446479788050

Ciphertext: df572f57ac514eeee9075bc0ff4d946a80cb16a6e8cd3e1bb686fabe543698dd8f62184060aecff758b29d92ed0e5a315579b47f6963260d5d52b7ba00ac47fd

IV: baf9137b5bb8fa896ca84ce1a98b34e5

## The Solution

Firstly, according to the general form of the elliptic curve and the calculation formula of point addition, the parameters of the curve are obtained.

The SageMath code is as follows

```
p = 101177610013690114367644862496650410682060315507552683976670417670408764432851
a1 = 0
a2 = 417826948860567519876089769167830531934 // 2
a3 = 3045783791
a4 = 177776968102066079765540960971192211603
Gx = 14374457579818477622328740718059855487576640954098578940171165283141210916477
Gy = 97329024367170116249091206808639646539802948165666798870051500045258465236698
a6 = Gy^2 + a1 * Gx * Gy + a3 * Gy - (Gx^3 + a2 * Gx^2 + a4 * Gx)
a6 = a6 % p
EC = EllipticCurve(Zmod(p), [a1, a2, a3, a4, a6])
G = EC(Gx, Gy)
print("G =", G)
```

We can then `Gn`

get the y coordinate given the x coordinate `Gn`

.

```
Gnx = 32293793010624418281951109498609822259728115103695057808533313831446479788050
Gn = EC.lift_x(Gnx)
print("Gn =", Gn.xy())
```

We can also see that the order of the curve is not a prime number, so we can use the Pohlig–Hellman algorithm to calculate `Gn`

the `G`

discrete logarithm of the sum, that is, `n`

```
ecOrder = EC.order()
print("EC order =", ecOrder)
F = factor(ecOrder)
print("F =", F)
```

The prime factorization of the curve order gives 7 prime factors. Only the first 5 values are small enough to directly calculate the discrete logarithm. Then you need to use `n`

the upper limit given in the question to enumerate the possible values one by one to find it `n`

.

```
#we only need the first 5 factor
primes = [9, 59, 14771, 27733, 620059697]
dlogs = []
product = 1
for fac in primes:
t = ecOrder // fac
dlog = discrete_log(t*Gn, t*G, operation="+")
dlogs.append(dlog)
print("factor: ", fac, ", Discrete Log: ", dlog)
product = product * fac
L = crt(dlogs, primes)
print("L =", L)
print("check L =", L * G == Gn)
print("product =", product)
n = L
while (n <= 38685626227668133590597631):
if (n * G == Gn):
print("Found n =", n)
break
else:
n = n + product
print("n =", n)
```

After obtaining it `n`

, apply the AES decryption method to get the plain text of the Flag.

```
from Crypto.Cipher import AES
from hashlib import sha1
iv = bytes.fromhex("baf9137b5bb8fa896ca84ce1a98b34e5")
cipherText = bytes.fromhex("df572f57ac514eeee9075bc0ff4d946a80cb16a6e8cd3e1bb686fabe543698dd8f62184060aecff758b29d92ed0e5a315579b47f6963260d5d52b7ba00ac47fd")
key = sha1(str('PUT_n_HERE').encode('ascii')).digest()[0:16]
cipher = AES.new(key, AES.MODE_CBC, iv)
plainText = cipher.decrypt(cipherText)
print ("plainText=", plainText)
```