We were provided with two essential files: ‘msg.enc’, holding a cryptic message, and ‘chall.py’, the encryption script. Our task is to decode the message by writing a script that reverses the encryption process outlined in ‘chall.py’
Warning
The information provided on this site is intended for educational purposes only. While we strive to offer accurate and up-to-date content regarding hacking and security, we cannot be held responsible for any misuse or illegal activity conducted with the knowledge gained from this site. Users are solely responsible for their actions and should use this information ethically and within the boundaries of the law.
Solving the challange
In this challenge we have 2 main files, a python script(chall.py) and a text file(msg.enc). The python script has the following content:
import string
from secret import MSG
def encryption(msg):
ct = []
for char in msg:
ct.append((123 * char + 18) % 256)
return bytes(ct)
ct = encryption(MSG)
f = open('./msg.enc','w')
f.write(ct.hex())
f.close()
This script encrypts a variable called MSG that’s being imported from secret, which we don’t have access to.
Brute Force Approach
The easiest way to solve it (my opinion), is to just brute force all the characters.
hex_txt = "6e0a9372ec49a3f6930ed8723f9df6f6720ed8d89dc4937222ec7214d89d1e0e352ce0aa6ec82bf622227bb70e7fb7352249b7d893c493d8539dec8fb7935d490e7f9d22ec89b7a322ec8fd80e7f8921"
result = ""
cyp_txt = bytes.fromhex(hex_txt)
for char in cyp_txt:
for asc in range(33, 126):
if ((123 * asc + 18) % 256) == char:
result += chr(asc)
break
print(result)
Although this way is really simple to understand, this has a problem, the more characters we have more time we will consume to decrypt it. In that challenges this is not a problem but we have a smarter approach, a mathematical approach.
Mathematical Approach
First let’s simplify the problem, assume we have the following function:
\( f(x) = 2x +1 \)
Taking a \( x=1 \) we will have the corresponding \( f(x) \):
\( f(1)=2.1+1=3 \)
If we want to reverse this process we just need to find the \( f^{-1}(x) \) , which in this case is a really simple process:
\( f^{-1}(x)=\frac{(x-1)}{2} \)
So we can do a similar process to the function that is being used to encrypt the message. But there is as problem, the modulo. Let’s first return to the original encryption script and analyse why the modulo is being used in the first place.
import string
from secret import MSG
def encryption(msg):
ct = []
for char in msg:
ct.append((123 * char + 18) % 256) #modulo
return bytes(ct)
ct = encryption(MSG)
f = open('./msg.enc','w')
f.write(ct.hex())
f.close()
So we have this operation:
\( (123\;.\; char + 18) \)
There, char is the number that represents a ascii character, so char is a number between 0 and 255, we multiply this number by 123 and then we sum 18 to it, but, the result of all this operations needs to be a number between 0 and 255 also, to ensure this we use the modulo operation.
Ok, now your goal is just to reverse the equation, but, how can we reverse the modulo ?
What is Modulo?
“In computing, the modulo operation returns the remainder or signed remainder of a division, after one number is divided by another”
https://en.wikipedia.org/wiki/Modulo
So, modulo returns to us the remainder of a certain division. But how can we reverse it ?
To do that we can use the Modular multiplicative inverse, this gives us the following, The modular multiplicative inverse of an integer a modulo m is an integer b such that:
\( ab≡1 (mod x)ab≡1(modx) \)
So in our case, we have:
\( 123 . b≡1 (mod 256)\)
We can simplify that concept:
\( 123.b=(n.256)+1\;\;\;n,b∈N \)
That way we are trying to find b, a natural number in a way that n is a natural number also.
Note: You can find a really good explanation of why that works here: https://planetcalc.com/3311/ and also, there is a calculator we can use to find the answer we need.
Using the calculator we find the modular multiplicative inverse of 123 modulo 256 is 179, so we can create a simple script to reverse the encrypted text:
hex_txt = "6e0a9372ec49a3f6930ed8723f9df6f6720ed8d89dc4937222ec7214d89d1e0e352ce0aa6ec82bf622227bb70e7fb7352249b7d893c493d8539dec8fb7935d490e7f9d22ec89b7a322ec8fd80e7f8921"
def decript(msg):
cyp_txt = []
for char in msg:
char = char - 18
char = 179 * char % 256
cyp_txt.append(char)
return bytes(cyp_txt)
cyp_txt = bytes.fromhex(hex_txt)
result = decript(cyp_txt)
print(result)