چالش ComplexProblem¶

صورت سوال¶
خب در صورت سوال گفته: از رمزنگاری RSA استفاده شده و این بار باید با اعداد مختلط سر و کله بزنیم...
یه فایل متنی بهمون دادن که محتواش اینه:
فایل متنی out.txt
¶
N = 47314254765672217716326132674
+ 275948221897758780728621214539i
e = 65537
ciphertext = -120974603478533287568533462088
+ -26598567903204264781472600457i
کلاس Gaussian Rational
¶
بیایم نگاهی به اسکریپت پایتون سوال بندازیم
شاید براتون سوال بشه این کلاس اصلا چی هست؟ در واقع توی ریاضیات، یک عدد گوسی گویا یک عدد مختلط به شکل
هست، که توی اون p و q هر دو اعداد گویا هستند. و همانطور که میدونید p قسمت Real یا حقیقی و q قسمت Imag یا موهومی هست.
و همچنین مشاهده میکنید که یکسری عملیات برای این کلاس تعیین شده
class GaussianRational:
def __init__(self, real: Fraction, imag: Fraction):
assert(type(real) == Fraction)
assert(type(imag) == Fraction)
self.real = real
self.imag = imag
def conjugate(self):
return GaussianRational(self.real, self.imag * -1)
def __add__(self, other):
return GaussianRational(self.real + other.real, self.imag + other.imag)
def __sub__(self, other):
return GaussianRational(self.real - other.real, self.imag - other.imag)
def __mul__(self, other):
return GaussianRational(self.real * other.real - self.imag * other.imag, self.real * other.imag + self.imag * other.real)
def __truediv__(self, other):
divisor = (other.conjugate() * other).real
dividend = other.conjugate() * self
return GaussianRational(dividend.real / divisor, dividend.imag / divisor)
# credit to https://stackoverflow.com/questions/54553489/how-to-calculate-a-modulo-of-complex-numbers
def __mod__(self, other):
x = self/other
y = GaussianRational(Fraction(round(x.real)), Fraction(round(x.imag)))
z = y*other
return self - z
# note: does not work for negative exponents
# exponent is (non-negative) integer, modulus is a Gaussian rational
def __pow__(self, exponent, modulo):
shifted_exponent = exponent
powers = self
result = GaussianRational(Fraction(1), Fraction(0))
while (shifted_exponent > 0):
if (shifted_exponent & 1 == 1):
result = (result * powers) % modulo
shifted_exponent >>= 1
powers = (powers * powers) % modulo
return result
def __eq__(self, other):
if type(other) != GaussianRational: return False
return self.imag == other.imag and self.real == other.real
def __repr__(self):
return f"{self.real}\n+ {self.imag}i"
ساختن کلید¶
حالا همونطور که میبینید دو تا تابع داریم که زحمت ساختن کلید رو میکشن..
تابع get_gaussian_prime
¶
که میاد یک عدد اول گاوسی رو تولید میکنه
# gets a Gaussian prime with real/imaginary component being n bits each
def get_gaussian_prime(nbits):
while True:
candidate_real = randbits(nbits-1) + (1 << nbits)
candidate_imag = randbits(nbits-1) + (1 << nbits)
if isPrime(candidate_real*candidate_real + candidate_imag*candidate_imag):
candidate = GaussianRational(Fraction(candidate_real), Fraction(candidate_imag))
return candidate
تابع generate_keys
¶
اینم که عدد اولاشو از تابع بالا میگیره و کلید رو تولید میکنه
def generate_keys(nbits, e=65537):
p = get_gaussian_prime(nbits)
q = get_gaussian_prime(nbits)
N = p*q
return (N, e) # (N, e) is public key
تابع encrypt
¶
حالا تابعی که رمزنگاری میکنه رو هم میتونیم ببینیم
def encrypt(message, public_key):
(N, e) = public_key
return pow(message, e, N)
روش حل¶
خب بباین دقت کنیم ببینیم چه بلایی سر فلگ میاد و چجوری رمز میشه و چیکار باید بکنیم اصلا؟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
خب در مرحله اول میاد فلگو میخونه و بعدش یک کلید عمومی ۶۴ بیتی تولید میکنه و بعدش میاد همانطور که کد بالا رو هایلایت کردم میاد فلگو دو تکه میکنه و در قالب گاوسی گویا به عنوان پیامی که قراره رمز بشه تبدیل میکنه.
بعدش میاد encrypt میکنه.
خب ما کار میکنیم که همیشه برای رمزگشایی RSA استفاده میکردیم با این تفاوت که این بار در قالب گوسی گویا باید حمله کنیم و در آخر باید حواسمون جمع باشه که وقتی فلگ رو بدست اوردیم ( که در حقیقت یک عدد مختلط هست ) قسمت Real یا حقیقی و قسمت Imag یا موهومی اون رو جداگونه تبدیل به بایت کنیم و بعد فلگ نهایی رو بدست بیاریم.
خب اگه یادتون باشه N در قالب یک عدد مختلط داده شده خب حالا به نظرتون ما چجوری Phi این عدد رو محاسبه کنیم؟ جواب اینه باید Norm اون رو محاسبه کنیم و بعدش از طریق اون Phi رو محاسبه کنیم.
محاسبه Norm¶
Norm عدد زیر به فرم گوسی گویا
برابر است با:
solve.py | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
بعد از اینکه نرم N رو بررسی کردیم میبینیم که اول نیست بنابراین با Factordb.com یا SageMath کار رو پیش میبریم و بنابراین میتونیم دو عدد اول p و q رو پیدا کنیم که حاصل ضربشون بشه برابر N.
حالا داریم:
بعد میایم اون پیام رمز شده به صورت عدد مختلط و N رو به در قالب گوسی گویا درنظر گرفته و در نهایت d رو محاسبه کرده و فلگ رو میکشیم بیرون به همین راحتی!
FLAG 
sdctf{g3t_r341_0bcef3a}
نویسنده