fr33f0r4ll

自分用雑記

TokyoWesterns CTF 2018 Revolutional Secure Angou 復習 ctf crypto

Revolutional Secure Angou 復習

https://ctftime.org/writeup/10865 Writeup見て復習。

RSA問題、珍しくRubyで書かれている。

require 'openssl'

e = 65537
while true
  p = OpenSSL::BN.generate_prime(1024, false)
  q = OpenSSL::BN.new(e).mod_inverse(p)
  next unless q.prime?
  key = OpenSSL::PKey::RSA.new
  key.set_key(p.to_i * q.to_i, e, nil)
  File.write('publickey.pem', key.to_pem)
  File.binwrite('flag.encrypted', key.public_encrypt(File.binread('flag')))
  break
end

僕はまったく分からなかったが、qの生成方法が普通と違うので不備があることに気付けるらしい。

通常のRSAの手順は以下のようになる。

  1. ランダムに2つの素数を生成、pq
  2. p-1q-1に対して素な整数e, public exponentを選ぶ、たいてい0x10001, 65537になっている。
  3. d, private exponentを計算する。これはd = e^{-1}\ mod\ (p-1)(q-1)で計算される。
  4. n = pqを計算し、(n, e)を公開鍵、d秘密鍵にする。

普通はqもランダムに生成するが、このスクリプトではq = OpenSSL::BN.new(e).mod_inverse(p)となっている。
つまり、q = e^{-1}\ mod\ pで生成されている。
この式を変形するとqe = 1\ mod\ pとなり、qe = pk + 1と表せる(kは任意の整数)。
ここで、両辺にpをかける。
すると、pqe = kp^2 + pとなる。
n = pqなので、pqeは知ることができる。
つまり、kp^2 + p - ne = 0という2次方程式になる。
これによりpを求めることができる。

pが分かればdを計算できる、これで暗号化されたフラグを復号できる。