from Crypto.Util.number import getPrime, getRandomRange, bytes_to_longFLAG =bytes_to_long(open("flag.txt", "rb").read())N = FLAG.bit_length()+2**7m =sorted([ getPrime(N) for _ inrange(5) ])share = []while ((m[1]*m[2]*m[3]< m[0]*m[3]*m[4]) and m[4]<m[3]): m[4]=getPrime(N)M = m[1]*m[2]alpha =getRandomRange(2, M)k =4for i inrange(k): s = (FLAG + alpha*m[0]) % m[i+1] share.append(s)withopen("out.txt", 'w')as f: f.write(f"Public (m0): {hex(m[0])}\n\n")for i inrange(len(share)): f.write(f"Share {i} (s{i}, m{i+1}): ({hex(share[i])}, {hex(m[i+1])})\n")
We are given the values of quite a few variables in the out.txt file.
Reading the code for chal.py, we can see that it encrypts the flag with the use of nearly all values given in out.txt. Should be fairly simple to decrypt the flag.
Analyzing chal.py
The flag is first converted into a long integer. Then a value N is assigned <number of bits of the flag> + 2**7. It then randomly generates 5 different prime numbers with N bits and stores them into a sorted list m.
FLAG =bytes_to_long(open("flag.txt", "rb").read())N = FLAG.bit_length()+2**7m =sorted([ getPrime(N) for _ inrange(5) ])
Then is just loops through until m[4] is a prime number such that m[0]*m[3]*m[4] is more than m[1]*m[2]*m[3], and m[4] is more than m[3]. This part isn't really important.
while ((m[1]*m[2]*m[3]< m[0]*m[3]*m[4]) and m[4]<m[3]): m[4]=getPrime(N)
It then generates a number and assigns it to the variable alpha. We can't really find the value of alpha as it is a random number and M is a pretty large number.
M = m[1]*m[2]alpha =getRandomRange(2, M)k =4
4 values are then generated and stored in s. This is the important part of the encryption. Last few lines are just to write out the values to out.txt.
for i inrange(k): s = (FLAG + alpha*m[0]) % m[i+1] share.append(s)
From this part of the code, we have all the values of every variable except for alpha.
Take note that the portion s = (FLAG + alpha*m[0]) % m[i+1] repeats 4 times, with different s results, using m[1] to m[4] as the modulus at each iteration, and (FLAG + alpha*m[0]) being the same at each iteration (the number being modulo is the same each time).
So we can form 4 equations given the values we got from out.txt:
s0 = (FLAG + alpha*m[0]) % m1
s1 = (FLAG + alpha*m[0]) % m2
s2 = (FLAG + alpha*m[0]) % m3
s3 = (FLAG + alpha*m[0]) % m4
If you are unfamiliar with these equations, we can basically solve for the value of (FLAG + alpha*m[0]) using the Chinese Remainder Theorem (CRT).
Since I haven't officially study Number Theory and I mostly read about these algorithms online, I may not be the best at explaining it. You can search on Youtube or Wikipedia on how it works.
We can easily implement CRT in Python by doing so:
from sympy.ntheory.modular import crtx =crt(mod,res)[0] # mod and res has to be lists
We can substitute mod for a list containing m1,m2,m3,m4.
We can substitute res for a list containing s0,s1,s2,s3.
With this, we retrieved the value of (FLAG + alpha*m[0]).
To get value of FLAG, notice how m0 is an extremely large number and how it is multiplied to alpha. Thus, we can get rid of the alpha*m[0] part just by performing mod m0 on the value!
(FLAG + alpha*m0) % m0 = FLAG % m0 + (alpha*m0) % m0(alpha*m0) % m0 =0FLAG % m0 = FLAG # Since it is most likely that FLAG < m0 as m0 is an extremely large number# Therefore(FLAG + alpha*m0) % m0 = FLAG