# XMASSpirit Now that elves have taken over Santa has lost so many letters from kids all over the world. However, there is one kid who managed to locate Santa and sent him a letter. It seems like the XMAS spirit is so strong within this kid. He was so smart that thought of encrypting the letter in case elves captured it. Unfortunately, Santa has no idea about cryptography. Can you help him read the letter? ## Flag HTB{4ff1n3_c1ph3r_15_51mpl3_m47h5} - See letter.pdf ## How to solve - It's a known plaintext attack. - The encryption works by applying `(a*byte+b)%n` for each byte of the pdf. - Where `a` and `b` remain static during the entire encryption process. - The PDFv5 Header is known (`00000000: 2550 4446 2d31 2e35 0a25 e2e3 cfd3 0a37 %PDF-1.5.%.....7`) - Constraint 1: Factor `a` has to be a number between 1..256 while not sharing a common divisor with 256 - Constraitn 2: Factor `b` has to be a number between 1..256 - So it's possible to attack the encryption by iterating and trying to create a pair (a, b) that matches the entire encrypted pdf header. ```python def get_factors(ct:bytes, n:int=256) -> (int, int): ''' find a and b for n and ct ''' # first generate a list of all numbers without common divisor with 256 nogcds = [ x for x in range(1, n) if gcd(x, n) == 1 ] for b in range(1, n): for a in nogcds: for i, enc in enumerate(header): candidate = (a * enc + b) % n if candidate != ct[i]: break if(i+1 == len(header)): print(f'Solved: a={a},b={b}') return (a,b) print(f'No solution found.') return (0,0) ``` - When the factors are found, simply create a lookup table of all values and substitute each byte in the ciphertext. ```python def decrypt(ct:bytes, lut:dict) -> bytes: ''' decrypt the file using the lookup table ''' res = b'' for byte in ct: dec = lut[byte] res += bytes([dec]) return res ``` ## Notes ### Encryption code analysis: - Choose a `randint` `a` from `1` to `mod`, that is not divisible by mod. - Choose a `randint` `b` from `1` to `mod`. - for each byte in `dt` - calculate `(a * byte + b) % mod` - append to output bytes - return bytes when done - `s_next = (a * s_prev + b) mod p` is a linear congruential generator prng