Reverse Engineering/Cryptography

Cryptohack - Adrien’s Signs

We are given two files, source.py and output.txt.

source.py shows the source code that Adrien used to hide the flag, and is given as:

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])
    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


print(encrypt_flag(FLAG))

The encrypt_flag function iterates through each byte of the flag and converts it to its 8-bit binary representation. Then, the function iterates through each bit and generates a number based on whether that bit is ‘1’ or ‘0’, appending said number to the ciphertext array. For each bit:

output.txt contains the 224-element array generated from source.py.

Therefore, for each of the numbers in the ciphertext that represent a bit of the flag, we need to find a way to distinguish numbers representing $a^e$ from their additive inverses.

Note that due to $p$ being a prime number, we can use the Legendre Symbol to check if $a$ is a quadractic residue mod $p$. The definition of a quadractic residue is:

Legendre’s Symbol states that, for a prime number $p$:

Since $288260533169915^\frac{1007621497415250}{2} \equiv 1 \pmod{1007621497415251}$, we can confirm that $a$ is a quadractic residue mod $p$.

Remember that $p \equiv 3 \pmod{4}$. From the first supplement of quadractic reciprocity, we know that the negative of a quadractic residue modulo $p$, $p \equiv 3 \pmod{4}$, will always be a non-residue and vice-versa. This means we can use Legendre’s Symbol to differentiate between a number and its additive inverse mod p.

However, the numbers in the ciphertext are powers of $a$ in the range $(1, p)$. Note that, for a quadractic residue $a$, there exists a value $x$ such that $x^2 \equiv a \pmod{p}$.

If we exponentiate $a$ to a value $k$; $k > 0$:

$(x^2)^k \equiv a^k \pmod{p}$

$ x^{2k} \equiv a^k \pmod{p}$

Therefore, the quadractic residue property holds for powers of $a$, and thus we can use Legendre’s Symbol to differentiate between the 1 and 0 bits in the ciphertext. Calculate Legendre’s Symbol for each element in the array, and replace it with the 1 or 0 bit accordingly:

flag = ""
leg_exp = int((p-1) / 2)

for bit in ciphertext:
    legendre = pow(bit, leg_exp, p)
    if legendre == 1:
        flag += "1"
    else:
        flag += "0"

Which converts the ciphertext back into the bits of our flag despite the randomness of e.