Xmas Spirit
Contents
We get given challenge.py and encrypted.bin. Analysing challenge.py:
import random
from math import gcd
def encrypt(dt):
	mod = 256
	while True:
		a = random.randint(1, mod)
		if gcd(a, mod) == 1:
			break
	b = random.randint(1, mod)
	res = b''
	for byte in dt:
		enc = (a * byte + b) % mod
		res += bytes([enc])
	return res
dt = open('letter.pdf', 'rb').read()
res = encrypt(dt)
f = open('encrypted.bin', 'wb')
f.write(res)
f.close()It calculates two random values, and . For every byte in the plaintext file, it then calculates
And appends the result of that as the encrypted character in encrypted.bin.
Analysis
The plaintext file appears to be letter.pdf, and using this we can work out the values of  and  because we know the first 4 bytes of every PDF file are %PDF. We can extract the first two bytes of encrypted.bin and compare to the expected two bytes:
with open('encrypted.bin', 'rb') as f:
    res = f.read()
print(res[0])
print(res[1])
print(ord('%'))
print(ord('P'))Gives us
13
112
37
80So we can form two equations here using this information:
We subtract (2) from (1) to get that
And we can multiply both sides by the modular multiplicative inverse of 43, i.e. , which is , to get that
And then we can calculate :
Solution
So now we have the values for and , it's simply a matter of going byte-by-byte and reversing it. I created a simple Sage script to do this with me, and it took a bit of time to run but eventually got the flag.
with open('encrypted.bin', 'rb') as f:
    res = f.read()
final = b''
R = IntegerModRing(256)
for char in res:
    b = bytes([ (R(char) - R(160)) / R(169) ])
    print(b.decode('latin-1'), end='')
    final += b
with open('answer.pdf', 'wb') as f:
    f.write(final)And the resulting PDF has the flag HTB{4ff1n3_c1ph3r_15_51mpl3_m47h5} within.
Last updated
Was this helpful?
