Các cuộc thi năm 2019 ##################### AceBear ******* Baby RSA ======== Đề bài .. code-block:: python # rsa.py from Crypto.Util.number import * from secret import flag m = bytes_to_long(flag) p = getPrime(512) q = getPrime(512) n = p*q e = 65537 c = pow(m, e, n) print(n) # 132991872691788324082134861997953579720626276400340540687013665099477551458348129102088618361745158673111757871083783880384786818716675179609957267487624993539275409316283860268944400754318665280566429956092526555947286266806591767802818223484766666271142927737412289284611614382748008696676464334157695348471 print(c) # 51298575439582965784709335152059190835305126166438646589369499569428503835480418841408132266294091481013029021796067865137829386370176771358549523435135941877535688535317287350930103706346511719290416785053872504275498831270025102211793188751664805369414883387849038010293938521738911310864582949611581363258 print(pow(p+q, 2019, n)) # 116622952696503724444465816906812927416603315297598995734109952470693593204299624097288573735780464942963720997719694033378973971604112334413336782598075611956878592757766346915810900585142701963781432186914454664547551508332077962977944352243565906344660561255453917679867097810681750809061744116605905787747 print(pow(p+2019, q, n)) # 46935581819524717607675319301313485106684889957138298327245990937934310422542055504175491111118389178173005337213903985686712577881019021348501335888175248295397612880683801733649468701485843002169345784241756189697901370624950199354359977266595488202827970067500373575114835718127956891051157026649793602861 Đặt :math:`c_1 = (p + q)^{2019}`, :math:`c_2 = (p + 2019)^{q}`. Khi đó :math:`(p + 2019)^q - c_2` chia hết cho :math:`n`, suy ra :math:`(p + 2019)^q - c_2` chia hết :math:`q`, và :math:`(p + 2019)^q \equiv c_2 \bmod q`. Theo định lý Fermat, :math:`(p + 2019)^q \equiv p + 2019 \bmod q`, suy ra :math:`p + 2019 \equiv c_2 \bmod q`, và :math:`p + 2019 - c_2` chia hết :math:`q`. Ta cũng có :math:`n` chia hết cho :math:`q` nên :math:`a \cdot n + b \cdot (c_2 - p - 2019)` chia hết :math:`q`, với :math:`a`, :math:`b` là các số nguyên bất kì. Ta có :math:`a \cdot n + b \cdot (c_2 - p - 2019) = a \cdot n + b \cdot (c_2 - 2019) - b \cdot p` (1) nên ta sẽ tìm số :math:`a`, :math:`b` để :math:`a \cdot n + b \cdot (c_2 - 2019)` trở nên gọn nhất có thể. Vì :math:`\gcd(n, c_2 - 2019) = 1` nên ta dùng thuật toán Euclid mở rộng để tìm :math:`a`, :math:`b` để :math:`a \cdot n + b \cdot (c_2 - 2019) = 1`. Thay :math:`a` và :math:`b` vào (1) ta có :math:`1 - b \cdot p` chia hết :math:`q` nên :math:`b \cdot p - 1 = k \cdot q`, hay :math:`b \cdot p = k \cdot q + 1` (2). Ta lại có :math:`(p + q)^{2019} \equiv c_1 \bmod n` .. math:: & \Longrightarrow (p + q) \cdot 2019 \equiv c_1 \bmod q \\ & \Longrightarrow (p + q) \cdot 2019 \cdot b^{2019} ≡ c_1 \cdot b^{2019} \bmod n \\ & \Longrightarrow (b \cdot p + b \cdot q)^{2019} \equiv (c_1 \cdot b^{2019}) \bmod n. Thay (2) vào đây ta được :math:`(1 + (k + b) \cdot q)^{2019} \equiv (c_1 \cdot b^{2019}) \bmod q`. Vì :math:`1 + (k + b) \cdot q \equiv 1 \bmod q` nên :math:`(c_1 \cdot b^{2019}) \bmod n - 1` chia hết :math:`q`, suy ra :math:`\gcd(n, (c_1 \cdot b^{2019}) \bmod n - 1) = q` vì :math:`(c_1 \cdot b^{2019}) \bmod n - 1` không chia hết :math:`n`. Như vậy tìm ước chung lớn nhất giữa :math:`n` và :math:`(c_1 \cdot b^{2019 - 1}) \bmod n` sẽ được :math:`q`. Từ đó tính :math:`p` và giải mã được bài toán. .. code-block:: python n = 132991872691788324082134861997953579720626276400340540687013665099477551458348129102088618361745158673111757871083783880384786818716675179609957267487624993539275409316283860268944400754318665280566429956092526555947286266806591767802818223484766666271142927737412289284611614382748008696676464334157695348471 from Crypto.Util.number import * c = 51298575439582965784709335152059190835305126166438646589369499569428503835480418841408132266294091481013029021796067865137829386370176771358549523435135941877535688535317287350930103706346511719290416785053872504275498831270025102211793188751664805369414883387849038010293938521738911310864582949611581363258 # print(pow(p+q, 2019, n)) c1 = 116622952696503724444465816906812927416603315297598995734109952470693593204299624097288573735780464942963720997719694033378973971604112334413336782598075611956878592757766346915810900585142701963781432186914454664547551508332077962977944352243565906344660561255453917679867097810681750809061744116605905787747 # print(pow(p+2019, q, n)) c2 = 46935581819524717607675319301313485106684889957138298327245990937934310422542055504175491111118389178173005337213903985686712577881019021348501335888175248295397612880683801733649468701485843002169345784241756189697901370624950199354359977266595488202827970067500373575114835718127956891051157026649793602861 x = c2 - 2019 def isqrt(n): x = n y = (x + n // x) // 2 while y < x: x = y y = (x + n // x) // 2 return x def xgcd(b, a): x0, x1, y0, y1 = 1, 0, 0, 1 while a != 0: q, b, a = b//a, a, b%a x0, x1 = x1, x0 - q*x1 y0, y1 = y1, y0 - q*y1 return b, x0, y0 def mulinv(a, b): """return x such that (x * a) % b == 1""" g, x, _ = xgcd(a, b) if g == 1: return x % b _, a, b = xgcd(n, c2-2019) tmp = (1-c1*b**2019) % n # print(xgcd(n, tmp)) q = 13167511664664654241879722275239314077796628288014993501946163865534098363688179601787128893069641975126584216420427952135663458656314745346906315477111831 p = n // q assert (p*q == n) phi = (p-1)*(q-1) d = mulinv(65537, phi) m = pow(c, d, n) print(long_to_bytes(m)) .. raw:: html