# M side [![hackmd-github-sync-badge](https://hackmd.io/nziWWgwhRIqcvypBlqd_Pg/badge)](https://hackmd.io/nziWWgwhRIqcvypBlqd_Pg) - Source code đề bài: ``` python from Crypto.Util.number import getStrongPrime, bytes_to_long as b2l, isPrime import os FLAG = os.getenv('FLAG', 'FLAG{hue_hue_hue}').encode() p = getStrongPrime(512) q = getStrongPrime(512) while not isPrime(4 * p * p + q * q): p = getStrongPrime(512) q = getStrongPrime(512) hint = 4 * p * p + q * q e = 65537 print(f"hint: {hint}") # n for wat? print(f"ct: {pow(b2l(FLAG), e, p * q)}") """ hint: 461200758828450131454210143800752390120604788702850446626677508860195202567872951525840356360652411410325507978408159551511745286515952077623277648013847300682326320491554673107482337297490624180111664616997179295920679292302740410414234460216609334491960689077587284658443529175658488037725444342064697588997 ct: 8300471686897645926578017317669008715657023063758326776858584536715934138214945634323122846623068419230274473129224549308720801900902282047728570866212721492776095667521172972075671434379851908665193507551179353494082306227364627107561955072596424518466905164461036060360232934285662592773679335020824318918 """ ``` - Nhìn vào code, ta thấy đề bài không cho `n = p*q` như các bài RSA thường thấy, thay vào đó lại cho giá trị `hint = 4p^2 + q^2`. Mặt khác, giá trị hint là số nguyên tố nên ta sẽ liên tưởng đến "Định lý Fermat về tổng của hai số chính phương", định lý này phát biểu: "Một số nguyên tố biểu diễn được dưới dạng tổng 2 số chính phương khi và chỉ khi số nguyên tố đó đồng dư với 1 modulo 4". - Có một thuật toán khá hiệu quả để biểu diễn số nguyên tố dạng p = 4k+1 thành tổng 2 số chính phương, chi tiết như sau: * Tìm số x thỏa mãn $x^2 \equiv -1\text{ (mod n)}$. Ta làm được việc đó bằng cách tìm một [Quadratic non-residue](https://en.wikipedia.org/wiki/Quadratic_residue) theo modulo p (a là một Quadratic non-residue mod p khi và chỉ khi $a^{\frac{p-1}{2}} \equiv -1 \text{ (mod p)}$), gọi là q, khi đó $x = a^{\frac{p-1}{4}}\text{ (mod p)}$. -- Áp dụng thuật toán Euclid để tìm UCLN của 2 số với 2 số p và x. Lấy 2 số dư đầu tiên mà nhỏ hơn căn bậc 2 của p, gọi là a và b. Khi đó $a^2 + b^2 = p$ - Trở lại bài toán, sau khi áp dụng thuật toán tên, ta tìm được 2 số, khi đó số chẵn chính là 2p, số lẻ chình là q. Có p và q, công việc còn lại trở nên rất nhẹ nhàng phải không nào ^^ - Sau đây là source code giải mã: ``` python import gmpy2 from Crypto.Util.number import long_to_bytes hint = 461200758828450131454210143800752390120604788702850446626677508860195202567872951525840356360652411410325507978408159551511745286515952077623277648013847300682326320491554673107482337297490624180111664616997179295920679292302740410414234460216609334491960689077587284658443529175658488037725444342064697588997 ct = 8300471686897645926578017317669008715657023063758326776858584536715934138214945634323122846623068419230274473129224549308720801900902282047728570866212721492776095667521172972075671434379851908665193507551179353494082306227364627107561955072596424518466905164461036060360232934285662592773679335020824318918 t = hint # find Quadratic non-residue def check(a,p): if pow(a,(p-1)//2,p) == p-1: return True for i in range(hint): if check(i,hint) == True: x = i break x = pow(x,(hint-1)//4,hint) # assert pow(x,2,hint) == hint - 1 c = gmpy2.iroot(hint,2)[0] while hint > c or x > c: hint,x = max(x, hint % x) , min(x,hint % x) p = hint // 2 q = x n = p * q phi = (p-1)*(q-1) print(long_to_bytes(pow(ct,pow(65537,-1,phi),n))) ``` Kết quả: ![](https://hackmd.io/_uploads/r1OkmkhNh.png)