# padrsa [InterKosenCTF2020] ###### tags: `InterKosenCTF2020` `crypto` ## 概要 フラグまたは任意のメッセージが任意の$e (3 \leq e \leq 65537)$でRSAで暗号化できる。 $N$は接続ごとにランダムに生成され、512-bitである。一方、接続は最大30秒しか持たない。 その間何回でも暗号化できるが、過去と同じ$e$は使えない。 また、$m$は次のようなパディングが付加される。 $m' \leftarrow (r_0|n) || m || r$ $n$はnonceで、暗号化ごとに1足される。$r$は64-bitの乱数で、次のように暗号化ごとに変化する。 $r' \leftarrow (r \ll 1) \oplus (n + 1)$ つまり、平文がよく分からん何かで挟まれる形になる。 ## 解法 まず考えるのはe=3にする方法だが、Nが512ビットな以上mが170-8\*9=98ビット=12バイトの必要があり、非現実的なので却下。 ここで$m$が自由に設定できることを考える。$m$を空にすると、$(r_0|n)||r$が暗号化される。これは9バイトなので、e=3などとすれば簡単に復号できることが分かる。したがって、以降付加されるパディングがすべて予測できる。 これにより、Franklin Reiter's Attackが適用できる。 今回、 $$ M_1 = (r_2[0] | n) || flag || r_2 = flag \times 2^{64} + h_1\\ M_2 = (r_3[0] | (n+1)) || flag || r_3 = flag \times 2^{64} + h_2 $$ より、 $$ M_1 = flag \times 2^{64} + h_2 + (h_1 - h_2) = M_2 + (h_1 - h_2) $$ となり、Franklin Reiter's Attackのパラメータは、 $a = 1, b = h_1 - h_2$ となる。 ```python= from sage.all import * from ptrlib import * def enc_flag(e): sock.sendlineafter('> ', '1') sock.sendlineafter('e: ', str(e)) sock.recvuntil(': ') return int(sock.recvline(), 16) def enc(e, m): sock.sendlineafter('> ', '2') sock.sendlineafter('e: ', str(e)) sock.sendlineafter('m: ', m.hex()) sock.recvuntil(': ') return int(sock.recvline(), 16) def gcd(a, b): while b: a, b = b, a % b return a.monic() def franklinreiter(C1, C2, e1, e2, N, a, b): P, X = PolynomialRing(Zmod(N), name='X').objgen() g1 = (a*X + b)**e1 - C1 g2 = X**e2 - C2 result = -gcd(g1, g2).coefficients()[0] return int(result) sock = Socket("localhost", 13001) #sock = Socket("0.0.0.0", 9999) sock.recvuntil(': ') N = int(sock.recvline()) n1 = 1 c1 = enc(5, b'') r1 = Integer(c1).nth_root(5) & ((1 << 64) - 1) C1 = enc_flag(3) # M1 = (r2[0]|nonce)||flag||r2 C2 = enc_flag(7) # M2 = (r3[0]|nonce')||flag||r3 r2 = ((r1 << 1) ^ 2) & ((1 << 64) - 1) r3 = ((r2 << 1) ^ 3) & ((1 << 64) - 1) for l in range(40, 50): h2 = (((r2>>56)|2) << (l*8+64)) + r2 h3 = (((r3>>56)|3) << (l*8+64)) + r3 m = franklinreiter(C1, C2, 3, 7, N, 1, h2 - h3) print(int.to_bytes(m, byteorder='big', length=64)) ``` ## 意見・感想 - 良問 - hardで良さそう。 - 512-bitのNは解かれる可能性がなきにしもあらず...?