[HITCON CTF 2019 Quals] Lost Modulus Again

prob.py

from Crypto.Util.number import *


class Key:
    def __init__(self, bits):
        assert bits >= 512
        self.p = getPrime(bits)
        self.q = getPrime(bits)
        self.n = self.p * self.q
        self.e = 0x100007
        self.d = inverse(self.e, (self.p-1)*(self.q-1))
        self.dmp1 = self.d%(self.p-1)
        self.dmq1 = self.d%(self.q-1)
        self.iqmp = inverse(self.q, self.p)
        self.ipmq = inverse(self.p, self.q)

    def encrypt(self, data):
        num = bytes_to_long(data)
        result = pow(num, self.e, self.n)
        return long_to_bytes(result)

    def decrypt(self, data):
        num = bytes_to_long(data)
        v1 = pow(num, self.dmp1, self.p)
        v2 = pow(num, self.dmq1, self.q)
        result = (v2*self.p*self.ipmq+v1*self.q*self.iqmp) % self.n
        return long_to_bytes(result)

    def __str__(self):
        return "Key([e = {0}, n = {1}, x = {2}, y = {3}])".format(self.e, self.d, self.iqmp, self.ipmq)

def main():
    key = Key(1024)
    flag = open('flag').read()
    encrypt_flag = key.encrypt(flag)
    assert key.decrypt(encrypt_flag) == flag
    print key
    print encrypt_flag.encode('hex')


if __name__ == '__main__':
    main()

output

6
84329776255618646348016649734028295037597157542985867506958273359305624184282146866144159754298613694885173220275408231387000884549683819822991588176788392625802461171856762214917805903544785532328453620624644896107723229373581460638987146506975123149045044762903664396325969329482406959546962473688947985096

In this problem, $e, d, iqmp, ipmq$ is given. To recover flag from encrypt_flag, it is enough to find $n$.

 

Let's consider below three equations.

 

$ed-1= k\phi(n) \; (Equation 1)$

$\phi(n) = n - p - q + 1 \; (Equation 2)$

$p \times ipmq + q \times iqmp = n + 1 \; (Equation 3)$

 

Using this equation, we can get a diophantine equation $(ipmq-1) \times p + (iqmp - 1) \times q = (ed-1)/k$.

 

Since $k < e$, it is enough to check few kinds of $k$.

 

Solver.py

from Crypto.Util.number import *

def gcd(a, b):
  while(b): 
    a,b = b, a % b 
  return a 

def mysqrt(d):
  st = 1
  en = 10**1300
  while st<=en:
    mid = (st+en)//2
    if mid*mid == d: return mid
    if mid*mid < d: st=mid+1
    else: en=mid-1
  return -1

def egcd(a1, a2):
    x1, x2 = 1, 0
    y1, y2 = 0, 1
    while a2:
        q = a1 // a2
        a1, a2 = a2, a1 - q * a2
        x1, x2 = x2, x1 - q * x2
        y1, y2 = y2, y1 - q * y2
    return (x1, y1, a1)

e =   1048583
d =   20899585599499852848600179189763086698516108548228367107221738096450499101070075492197700491683249172909869748620431162381087017866603003080844372390109407618883775889949113518883655204495367156356586733638609604914325927159037673858380872827051492954190012228501796895529660404878822550757780926433386946425164501187561418082866346427628551763297010068329425460680225523270632454412376673863754258135691783420342075219153761633410012733450586771838248239221434791288928709490210661095249658730871114233033907339401132548352479119599592161475582267434069666373923164546185334225821332964035123667137917080001159691927
enc = 6315517144108346181816723099897023675574911374735398936591833706590364258184564710827234427731055048559822607765825888615252018165526396090041236515481884097316115657845863616027191241546872931338194871262588098949428397377758354022592306745947669728354322461011070818767686781572984901259034033895184947744496886943392083163678583781999851929812332715335746883110069495497948728241194518127509291959160766882315610259762352662845983222877441386838765184047248466927144181212035420321292287216414973587365695429489044345623525454703093721722072717560946535366845119502057231317372617085049803374310078177219696035587
xx=  e*d-1


#iqmp bit_length : 1022
iqmp = 22886390627173202444468626406642274959028635116543626995297684671305848436910064602418012808595951325519844918478912090039470530649857775854959462500919029371215000179065185673136642143061689849338228110909931445119687113803523924040922470616407096745128917352037282612768345609735657018628096338779732460743
#ipmq bit_length : 1024
ipmq = 138356012157150927033117814862941924437637775040379746970778376921933744927520585574595823734209547857047013402623714044512594300691782086053475259157899010363944831564630625623351267412232071416191142966170634950729938561841853176635423819365023039470901382901261884795304947251115006930995163847675576699331

gg = gcd(iqmp-1,ipmq-1)

for k in range(1,e):
  if (e*d-1) % k == 0:
    phi_n = (e*d-1)//k
    if not (1<<2046) < phi_n < (1<<2048) : continue
    if phi_n % gg != 0: continue
    c = phi_n // gg
    a = (ipmq-1)//gg
    b = (iqmp-1)//gg
    # p*a + q*b = c
    pmod = inverse(a, b)*c%b
    for j in range(100000):
      p = pmod + j*b
      if p > (1<<1024): break
      if not isPrime(p): continue
      q = (c-p*a)//b
      assert(p*a+q*b==c)
      if (iqmp*q-1)%p == 0 and (ipmq*p-1)%q == 0:
        M = pow(enc,d,p*q)
        print(long_to_bytes(M))
        exit()


#p = 135136928230019073146158752709151576119155564982754768027494878210491711363872928718225319693774548227271767324623087432404412585662574641211148315864508708036871556964386141364368797168619283425834644924573664613109609076319077176698754203574237779054129492453503018443013301394555677417140681949745410143477
#q = 166564961597106229342966450443567005929416288372170308009700499465281616388542030734600089639466922805142577582894052957547174764252067983124558747593344882775630971023610755334859287415681252266825395627416912206349590353878868107848653100299011246746851490276537231636534462821659050996145878589643016881929
#M = pow(enc,d,p*q)
#print(long_to_bytes(M))



# hitcon{1t_is_50_easy_t0_find_th3_modulus_back@@!!@!@!@@!}

'CTF > Crypto' 카테고리의 다른 글

[2019 X-MAS CTF] Hashed Presents  (0) 2019.12.14
[2019 X-MAS CTF] DeFUNct Ransomware  (0) 2019.12.14
[HITCON CTF 2019 Quals] Very Simple Haskell  (0) 2019.10.14
[TWCTF 2019] M-Poly-Cipher  (0) 2019.09.02
[TWCTF 2019] Simple Logic  (0) 2019.09.02
[TWCTF 2019] real-baby-rsa  (0) 2019.09.02
  Comments