Gotam
Gotam
| Category | Difficulty | Score | Solves | First 🩸 |
|---|---|---|---|---|
| Crypto | Getting There 🤓 | 98 | 46 | Pwnguins |
Code / Description
Overview
This challenge is about exploiting a side-channel attack on an oracle that behaves differently based on the Legendre symbol of the flag bits. Before this, we need to factor a composite number to calculate the Legendre symbol easily. The overall process would be:
- get public info (n, t) and factor n to calculate the Legendre symbol
- gather data based on the flag bits
- extract the value (0,1) based on the Legendre symbol related to the flag bits
Challenge Analysis
This challenge has a remote instance that has two basic functionalities. Let's see the corresponding code
This is the menu we have, option p will give the public data (n,t), and option e will give us the encrypted flag. Let's see how the public data and encryption work.
This is the key generation part.
The gotam function will generate two 128 prime numbers and calculate a parameter $ n=p*q $. It will also generate a variable $ t $ that is a Quadratic Non-Residue modulus $ n $. The check_nr is intended to check this. If you want to know more about the Legendre symbol or what is quadratic residue, I highly recommend checking this link from cryptohack, especially the challenges Quadratic Residues, Legendre Symbol, and Modular Square Root.
To be brief, the Legendre symbol is calculated to check if a number is a quadratic residue modulus a prime number p. We call a number a quadratic residue if it has a square root modulus a prime number. If the modulus number is a composite number like $ n=p*q $ then to calculate the Legendre symbol, we need to have the factors of $ n $ and calculate the Legendre Symbol for each factor separately. If any of them is -1 modulus the factor, then the number is a quadratic non-residue modulus n.
And this is the flag encryption part.
The encryption part is quite interesting; it will convert the flag to binary format and will adjust it to match a 1024-bit message with 0 values for MSB bits. Then, it will calculate a value based on the 0,1 value of the flag bits.
Then it will print this output to the user, and this process will be done for every single bit of the flag.
Solution
It seems we need to tackle a quadratic residue problem in this challenge. By the rule, we know that
- \(\text{residue} × \text{residue} = \text{residue}\)
- \(\text{residue} \times \text{non-residue} = \text{non-residue}\)
- \(\text{non-residue} × \text{non-residue} = \text{residue}\)
We know that the variable $ t $ is a quadratic non-residue. We also have a definite quadratic residue value in our encryption:
Let's see what will happen based on the flag bit value (R is a random value):
\(bit=1 \rightarrow e = t^1 * R^2 = t * R^2 \quad (\text{quadratic non-residue})\)
\(bit=0 \rightarrow e = t^0 * R^2 = R^2 \quad (\text{quadratic residue})\)
Based on the rule mentioned, because $ R^2 $ is a quadratic residue, if it is multiplied by $ t $ (when the flag bit is 1), then the result (e) will be a quadratic non-residue. But if it is not multiplied by $ t $ (when the flag bit is 0), then the result will be a quadratic residue.
So all we need to do is to check if the sequence of $ e $ values for every flag bit is a quadratic residue or non-residue. To do this, we need to calculate the Legendre symbol of every $ e $ ciphertext. Because we are working modulus $ n $, which is a composite number $ n=p*q $, we can not simply calculate like the prime modulus. To that, we need to factor the $ n $ and calculate the Legendre Symbol modulus for each factor p,q separately. I used yafu to factor n, and it is feasible because n is 256 bits.
Now that we have the factors (p,q), we can easily check each ciphertext to determine the flag bit based on the quadratic residue or non-residue of the ciphertext.
This would be the function to check if the ciphertext is a quadratic residue or a non-residue
And to determine the flag bits, if the $ e $ value is a quadratic residue (the function output is 1), it means the flag bit is 0, so the 1 - check_rs() would be 0. On the other hand, if the $ e $ is a quadratic non-residue (the function output is 0), it means the flag bit is 1, so the 1 - check_rs() would be 1.
I wrote this code to read the ciphertexts (e value) from a file, check if they are quadratic residue or non-residue, and build the flag bits.
And here is the output of the code:




