# 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

- The vulnerability is 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`)
- From the encryption algorithm the followin constraints can be derived:
- Constraint 1: Factor `a` has to be a number between 1..256 while not sharing a common divisor with 256
- Constraint 2: Factor `b` has to be a number between 1..256
- So it's possible to attack the ciphertext by iterating and trying to create a	pair (a, b) that encrypts the pdf5 header bites in such a way that it matches the ciphertext.

```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
