0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Daily AlpacaHack: ECRSA Writeup

0
Last updated at Posted at 2026-02-22

ECRSA

Elliptic Curve x RSA = ECRSA

import os

# secp521r1 patemeter
p = 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
K = GF(p)
a = K(0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc)
b = K(0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00)
EC = EllipticCurve(K, (a, b))

while True:
    Q = EC.random_point()
    q = int(Q.xy()[0])
    R = 2*Q
    r = int(R.xy()[0])
    if is_prime(q) and is_prime(r):
        break

n = q*r
e = 65537
m = int.from_bytes(os.environ.get("FLAG", "Alpaca{dummy}").encode(), "big")
assert m < n
c = pow(m, e, n)

print("n = {}".format(n))
print("e = {}".format(e))
print("c = {}".format(c))

今回の楕円曲線のパラメータはsecp521r1(別名: NIST P-521)を使用しています。
secp521r1はSECG の SEC 2 で定義された素数体$\mathbb{F}_p$上の推奨曲線です。
secpはStandards for Efficient Cryptography(SEC)とprime field(p)を表します。
521は$p$のビット長を表しており、この曲線では、$p = 2^{\scriptstyle 521} - 1$が使われています。
r1は、rがverifiably at random(検証可能なランダム方式)を、1はその系列内でのバリエーション番号を表しています。これは、曲線パラメータの選定に恣意性が入りうるため、seed を公開し、その seed から SHA-1 を用いて係数$b$ を導出する手順も公開することで、第三者が同じ seed から同じ $b$ を再現・検証できるようにしたものです。
余談ですが、sepc256k1のkはKoblitzを表します。
https://www.secg.org/sec2-v2.pdf

解法

今回の問題において、$q = x(Q), r = x(2Q)$をそれぞれ整数とし、$q, r \in \mathbb{P}$となるように設定しています。
ここで重要なのは、$r$$q$$x$座標を2倍した位置にあるということです。これは、楕円曲線の2倍公式を使えば、$q, r$を示すことができます。

今回の曲線$y^2 \equiv x^3 + ax + b \pmod p$上の点$(x_1, y_1)$の2倍点$(x_2, y_2)$は以下の式で求められます。

\begin{align}
x_2 &\equiv \lambda^2 - 2x_1 \pmod p\\
y_2 &\equiv \lambda(x_2 - x_1) + y_1 \pmod p
\end{align}

ただし、$\lambda \equiv \frac{3x_1^2+a}{2y_1} \pmod p$とします。

$q = (q_x, q_y), r = (r_x, r_y)$とすると、

\begin{align}
r_x &\equiv \lambda^2 - 2q_x \pmod p\\
r_y &\equiv \lambda(r_x - q_x) + q_y \pmod p
\end{align}

となります。
ここで、

\begin{align}
r_x &\equiv \lambda^2 - 2q_x \\
&\equiv \left(\frac{3q_x^2+a}{2q_y} \right)^2 - 2q_x\\
&\equiv \frac{9q_x^4 + 6aq_x + a^2}{4q_y^2} - 2q_x \pmod p
\end{align}

となり、$y^2 \equiv x^3 + ax + b \pmod p $から$q_y^2 \equiv q_x^3 + aq_x + b \pmod p$と表すことができるので、

\begin{align}
r_x &\equiv \frac{9q_x^4 + 6aq_x + a^2}{4(q_x^3 + aq_x + b)} - 2q_x\\
&\equiv\frac{(9q_x^4 + 6aq_x^2 + a^2) - 8q_x(q_x^3 + aq_x + b)}{4(q_x^3 + aq_x + b)}\\
&\equiv \frac{q_x^4 - 2aq_x^2 - 8bq_x + a^2}{4(q_x^3 + aq_x + b)} \pmod p
\end{align}

と変形することができます。
今回の問題では、$q, r$ともに$x$座標のみを使用しています。
つまり、$n = qr$は以下のようになります。

$$
n \equiv qr \equiv q\cdot\frac{q_x^4 - 2aq_x^2 - 8bq_x + a^2}{4(q_x^3 + aq_x + b)} \pmod p
$$
となり、$n$$q$のみで表すことができました。

最後に、方程式として解くために少し変形しましょう。

$$
4n(q_x^3 + aq_x + b) - q(q_x^4 - 2aq_x^2 - 8bq_x + a^2) \equiv 0 \pmod p
$$
よって、未知の変数$q_x$を使って根を求め、$n = qr$を満たす$q$を見つけられたらそれを用いて復号すればフラグを得られます。

from Crypto.Util.number import long_to_bytes
from sage.all import *

n = 24489807923160829853331858278295353076882496748356437425136070159565438013983472411573830861255379509744527059864107405391335396070661875605498494586447825822788450364814932266675738776136998383491576779465083731669643596152181500936763824489148317369367655622357267302603914593581625372679508643581386912033877057
e = 65537
c = 2878521000528279319502304373550176174118970956553760958198895851295578685557304197481600194317208136193632870619822554981703968844914526643614371981441816886658546070361109613762488893788055957762778868012759138069722552457665235326670564609161988943959614368453819936924812599400584406309008222724731151234689436

p = 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
K = GF(p)
a = K(0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc)
b = K(0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00)
EC = EllipticCurve(K, (a, b))

R = PolynomialRing(K, "q")
q = R.gen()

poly = 4*K(n)*(q**3 + a * q + b) - q*(q**4 - 2*a*q**2 - 8*b*q + a**2)
poly = poly.monic()

roots = poly.roots(multiplicities=False)
if not roots:
    raise ValueError("No roots found")
for root in roots:
    r = n // int(root)
    if r * int(root) == n:
        q = int(root)
        break

phi = (q-1)*(r-1)
d = pow(e, -1, phi)
flag = pow(c, d, n)
print(long_to_bytes(flag).decode())

Flag: Alpaca{easier_cracked_ruined_suboptimal_algorithm}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?