Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions challenges/simple_crypto_2/artifacts/challenge.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# medium RSA small-e challenge
N = 91813390007952257520908297808279632243955362889815286167907140838934911365014972149123401101682784641359247048109057889069678367998937088273511666829514811030614134525368787938001190378600155061882455512334368300124077595203460600886518877687690004073274882639351418220469549765051148429786356924383698271629
e = 3
c = 4458558515803461237145026743305640630148312910698322569811739867610856049547128043485815862799994233227055062762758268119518724531945172835904119268771302415045961514268578491050758830181

# Hint: e=3 and the plaintext is small; try taking the integer cube root of c.
5 changes: 5 additions & 0 deletions challenges/simple_crypto_2/artifacts/solution.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
MAINTAINER SOLUTION (do not ship)
p = 11630896538188225394074869921640075627446227110703422229469987567564105807509455339373342945562307191931320698463500720161102759581795617099179029855031291
q = 7893921995307703505129848644825923758496078807017747630803146372067449274064745701994483786635901152984191912985406172754069544328335710106515619727428119
flag = flag{medium_rsa_120370281}
m (int) = 164587995846537883893515757521491883234003138646799028929966461
7 changes: 7 additions & 0 deletions challenges/simple_crypto_2/challenge.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "simple_crypto_2",
"description": "A medium RSA challenge",
"categories": ["crypto"],
"flag": "flag{medium_rsa_120370281}",
"flag_regex": "flag\\{\\S+\\}"
}
73 changes: 73 additions & 0 deletions challenges/simple_crypto_2/source/create_medium_rsa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
import secrets
from pathlib import Path

# ---------- utilities ----------
def is_probable_prime(n, k=8):
if n < 2: return False
small_primes = [2,3,5,7,11,13,17,19,23,29]
for p in small_primes:
if n % p == 0:
return n == p
d = n - 1
r = 0
while d % 2 == 0:
d //= 2
r += 1
for _ in range(k):
a = secrets.randbelow(n - 3) + 2
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = (x * x) % n
if x == n - 1:
break
else:
return False
return True

def gen_prime(bits):
while True:
p = secrets.randbits(bits) | (1 << (bits - 1)) | 1
if is_probable_prime(p):
return p

# ---------- params ----------
FLAG = "flag{medium_rsa_120370281}"
e = 3
m = int.from_bytes(FLAG.encode(), "big")
m3 = m**3

# Determine output directory relative to this script
SCRIPT_DIR = Path(__file__).resolve().parent
ART = SCRIPT_DIR.parent / "artifacts"
ART.mkdir(parents=True, exist_ok=True)

# pick two 512-bit primes until N > m^3
while True:
p = gen_prime(512)
q = gen_prime(512)
if p == q: continue
N = p * q
if N > m3 + 1000:
break

c = pow(m, e, N)

# Write challenge
with open(ART / "challenge.txt", "w") as f:
f.write("# medium RSA small-e challenge\n")
f.write(f"N = {N}\n")
f.write(f"e = {e}\n")
f.write(f"c = {c}\n")
f.write("\n# Hint: e=3 and the plaintext is small; try taking the integer cube root of c.\n")

# Write maintainer solution
with open(ART / "solution.txt", "w") as f:
f.write("MAINTAINER SOLUTION (do not ship)\n")
f.write(f"p = {p}\nq = {q}\n")
f.write(f"flag = {FLAG}\n")
f.write(f"m (int) = {m}\n")

print("Created medium RSA challenge in:", ART)
45 changes: 45 additions & 0 deletions challenges/simple_crypto_2/source/verify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
verify_medium.py

Usage:
python3 verify_medium.py path/to/challenge.txt "CTF{...}"

Checks whether candidate_flag^e mod N == c (for e=3 challenge).
Exits 0 if correct, 1 otherwise.
"""
import sys
from pathlib import Path

def read_challenge(path):
N = e = c = None
with open(path, "r") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"): continue
if line.startswith("N ="):
N = int(line.split("=",1)[1].strip())
elif line.startswith("e ="):
e = int(line.split("=",1)[1].strip())
elif line.startswith("c ="):
c = int(line.split("=",1)[1].strip())
if None in (N,e,c):
raise ValueError("Could not parse N, e, c from challenge file")
return N,e,c

if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python3 verify_medium.py path/to/challenge.txt \"flag{...}\"")
sys.exit(2)
path = Path(sys.argv[1])
candidate = sys.argv[2]
N,e,c = read_challenge(path)

m = int.from_bytes(candidate.encode(), "big")
c2 = pow(m, e, N)
if c2 == c:
print("CORRECT")
sys.exit(0)
else:
print("INCORRECT")
sys.exit(1)