Skip to content

Latest commit

 

History

History
150 lines (111 loc) · 5.1 KB

README.md

File metadata and controls

150 lines (111 loc) · 5.1 KB

RAS

Description

RAS is an ancient RSA like challenge for Christmas Day!

ras.py:

#!/usr/bin/env python3

from Crypto.Util.number import *
from flag import flag

def genparam(nbit):
	while True:
		a, b = getRandomRange(2, nbit), getRandomRange(32, nbit)
		if (a ** b).bit_length() == nbit:
			return a ** b

def genkey(nbit):
	p, q = [_ + (_ % 2) for _ in [genparam(nbit) for _ in '01']]
	while True:
		P = p + getPrime(31)
		if isPrime(P):
			while True:
				Q = q + getPrime(37)
				if isPrime(Q):
					return P, Q

def encrypt(m, pubkey):
	e = 0x10001
	assert m < pubkey
	c = pow(m, e, pubkey)
	return c

nbit = 512
P, Q = genkey(nbit)
pubkey = P * Q
flag = bytes_to_long(flag)
enc = encrypt(flag, pubkey)
print(f'pubkey = {pubkey}')
print(f'enc = {enc}')

output.txt:

pubkey = 56469405750402193641449232753975279624388972985036568323092258873756801156079913882719631252209538683205353844069168609565141017503581101845476197667784484712057287713526027533597905495298848547839093455328128973319016710733533781180094847568951833393705432945294907000234880317134952746221201465210828955449
enc = 11104433528952071860984483920122173351342473018268740572598132083816861855404615534742178674185812745207876206939230069251889172817480784782618716608299615251541018034321389516732611030641383571306414414804563863131355221859432899624060128497648444189432635603082478662202695641001726208833663163000227827283

Writeup

In order to find p and q we test all of the possible values of a and b of genparam function:

from Crypto.Util.number import isPrime


N = 56469405750402193641449232753975279624388972985036568323092258873756801156079913882719631252209538683205353844069168609565141017503581101845476197667784484712057287713526027533597905495298848547839093455328128973319016710733533781180094847568951833393705432945294907000234880317134952746221201465210828955449


def getb(a):
    lower = 500 // (a.bit_length())
    for b in range(lower, 1000):
        num = a ** b
        if num.bit_length() == 512:
            return b
        if num.bit_length() > 512:
            return -1


def solve():
    cands = []
    for a in range(2, 513):
        b = getb(a)
        if b not in range(32, 513):
            continue
        cands.append((a, b))

    print(len(cands))
    ans = []
    for a in cands:
        le = a[0] ** a[1]
        le += le % 2
        for b in cands:
            ri = b[0] ** b[1]
            ri += ri % 2

            if le * ri < N and (N - le * ri).bit_length() < 600:
                ans.append((a, b))

    print('Count:', len(ans))
    print('\n'.join(map(str, ans)))


if __name__ == '__main__':
    solve()

genb receives a variable a and returns a value of b such that a**b has 512 bits.

We find all such (a,b) pairs. Also, we know that N has about 1024 bits, but N - p * q will have less than 600 bits. So we do this additional test and will see that only one choice for {p,q} will remain at last.

Then we execute the following code to find P. We should run this code twice(one instance for each of the obtained 512-bit numbers) in parallel in order to find the 31 bit prime sooner.

N = 56469405750402193641449232753975279624388972985036568323092258873756801156079913882719631252209538683205353844069168609565141017503581101845476197667784484712057287713526027533597905495298848547839093455328128973319016710733533781180094847568951833393705432945294907000234880317134952746221201465210828955449
start = int(input())
cnt = 0
rem = 1 << 20

for i in range(2**30+1, 2**31, 2):
    rem -= 1
    if rem == 0:
        rem = 1 << 20
        cnt += 1
        print(cnt)
    if i % 6 in [1, 5] and N % (start + i) == 0:
        print(i)
        break

Note that:

  • The rem and cnt variables are used to monitor the progress. They don't play a role in finding proper i value
  • The i % 6 in [1, 5] is a weak test on i to be prime and improve the speed of the code.
  • For loop step length is 2 as i should be prime and thus not an even number.

In the case of 23**113 + 1 input to the code, it will print 1158518719 in the 40th step. So we add this value to 23**113 + 1 to obtain P and then divide N by P to obtain Q.

from Crypto.Util.number import long_to_bytes


N = 56469405750402193641449232753975279624388972985036568323092258873756801156079913882719631252209538683205353844069168609565141017503581101845476197667784484712057287713526027533597905495298848547839093455328128973319016710733533781180094847568951833393705432945294907000234880317134952746221201465210828955449
P = 23**113 + 1 + 1158518719
Q = N // P
enc = 11104433528952071860984483920122173351342473018268740572598132083816861855404615534742178674185812745207876206939230069251889172817480784782618716608299615251541018034321389516732611030641383571306414414804563863131355221859432899624060128497648444189432635603082478662202695641001726208833663163000227827283

phi = (P - 1) * (Q - 1)
d = pow(0x10001, -1, phi)
print(long_to_bytes(pow(enc, d, N)).decode())

It will print ASIS{RAS_iZ_51mpl!FI3D_RSA_sY573M!}