We are given the following Python code for encrypting the flag:
xxxxxxxxxx
from random import randint
a = 288260533169915
p = 1007621497415251
FLAG = b'crypto{????????????????????}'
def encrypt_flag(flag):
ciphertext = []
plaintext = ''.join([bin(i)[2:].zfill(8) for i in flag])
print(plaintext)
for b in plaintext:
e = randint(1, p)
n = pow(a, e, p)
if b == '1':
ciphertext.append(n)
else:
n = -n % p
ciphertext.append(n)
return ciphertext
The way that the encryption works is that if it encounters a bit with value "1" in the binary representation of the plaintext (or the flag itself), then it appends
The unintended solution, which is based on a naive "hunch" that we can only find the discrete log, or 1
. Hence, we have a solution in Sage, which takes advantage of the discrete_log
functionality:
xxxxxxxxxx
from sage.groups.generic import discrete_log
from tqdm import tqdm
out = <array in output.txt given>
a = 288260533169915
p = 1007621497415251
a = Mod(a, p)
flag = ""
for c in tqdm(out):
try:
discrete_log(c, a, bounds=(1, p))
flag += "1"
except ValueError:
flag += "0"
for i in range(0, len(flag), 8):
flag_original = flag[i:i + 8]
print(chr(int(flag_original, 2)), end="")
The above relies on a unproven assumption that there does not exist
The intended solution, however, relies on a "smarter" observation. We observe that the prime used is of the form 1
. So if
We have the above as