CTFにおける離散対数問題に対するアプローチ
CTFの暗号分野では、離散対数問題を利用したアルゴリズム(ElGamal暗号、Diffe-Hellman鍵共有など)がよく扱われる。本稿ではこの離散対数を高速に解く方法を備忘録としてまとめておく。
離散対数問題(DLP: Discrete Logarithm Problem)
素数 と定数 が与えられたとき
において、からを計算することは容易だが、その逆の、からを求めることは困難であることを、離散対数問題と呼ぶ。公開鍵暗号方式では、このことを安全性の根拠とした暗号アルゴリズムがいくつか考案されている。CTFでは、この離散対数を解き、暗号の秘密鍵を特定する問題が出題される。
離散対数に対するアプローチ
離散対数に対するアプローチとして、列挙法、Baby-step Giant-step algorithm、Pohlig–Hellman algorithmの3つの手法を紹介する。
列挙法
列挙法は最もシンプルな手法であり、上式において、に対して合同式が成り立つかどうかを一つひとつ確認していく方法である。ただし、の位数が大きいときは膨大な試行数になるため現実的ではない。オーダーは。
Baby-step Giant-step algorithm
Baby-step Giant-step algorithmは列挙法による試行数を削減したアルゴリズムであり、オーダーはとなる。
において、(、)として、以下の式を得る。
このアルゴリズムでは上式の両辺が一致するようにとを総当たりし、を求める。そうすることで、列挙法よりも試行数が少なくて済む。
Baby-step Giant-step algorithmの詳細な手順は以下のとおりである。
1.
2. を満たすすべてのについて(Baby-step):
1. を計算し、のペアをテーブルに保存する
3. を計算する
4.
5. からまで(Giant-step):
1. がテーブルの第二要素に含まれるかチェックする
2. もし含まれていれば、を返す
3. もしそうでなければ、とする
Pohlig–Hellman algorithm
Pohlig–Hellman algorithmは、
に対し、の素因数が小さいときに有効に働くアルゴリズムである。ここでとはオイラー特性関数であり、より小さい自然数のうちと互いに素なものの個数を示し、特にが素数の場合はとなる。
Pohlig–Hellman algorithmのアイデアとしては、の位数が大きすぎて総当たりが困難だったものを、の位数が小さな離散対数問題に分割して解き、後で結合するといったものである。
まず、を以下のように素因数分解する。
このとき、の値は小さい(英語では"smooth"という)ことが望ましい。
としたとき、それぞれのについてオイラーの定理より以下の計算を行う。
この合同式は最初に示した離散対数問題の形に帰着されるが、はよりも小さいため、比較的容易にを求めることが可能である(Baby-step Giant-step algorithmも組み合わせればより高速になる)。
これによりの値が定まると、が求まったことになる。
について、は互いに素なので、中国人剰余定理より、これらを満たす整数がを法として唯一つ定まる。こうして求まったが最初に示した離散対数問題の解となる(は素数であるため、の位数はである)。Pohlig–Hellman algorithmのオーダーはだが、が小さいほどより効率的となる。
Pohlig–Hellman algorithmを使った攻撃の回避策として、安全素数を使う方法がある。安全素数は、とがともに素数である場合におけるである。このとき、のほうはSophie Germain素数と呼ばれる。安全素数を使うことで、となり、が大きな素因数を持つことになるため、Pohlig–Hellman algorithmが有効に働かなくなる。安全素数が無限に存在するという予想は未だ証明されていないが、実用的には十分存在するといわれている。
実装例
離散対数問題を安全性の根拠としている暗号方式として、ElGamal暗号を取り上げる。ElGamal暗号では、素数、整数、乱数を選んで、
を計算し、を公開鍵、を秘密鍵とする。
暗号化フェーズでは、平文と乱数を用いて、以下のように暗号文を計算する。
復号フェーズでは、平文を以下のように算出する。
以上が、ElGamal暗号のアルゴリズムである。
今回は、ElGamal暗号の例題として、MMA CTF 1st 2015で出題された「Alicegame」という問題を扱う。問題より、ElGamal暗号における以下の値が判明している(本当は鍵がランダムに生成され、最適なpが引けるまでガチャを回す必要があるのだが今回はその部分を割愛)。
c1 = 1851635883910479967256646617880733235123029676545812189105888 c2 = 2279140729739532482438192630521498934347693926502811537441460 g = 1828219035112142373387222893932751631772945852477987101590090 y = 1012750243445446249248731524345776923711031192963358920130436 p = 3047318456124223787871095946374791137939076290647203431778747 phi_p = 2 * 3 * 7 * 281 * 585131 * 2283091 * 66558319 * 38812459031 * 8407411055293 * 8899182573469
の素因数が小さいので、Pohlig–Hellman algorithmを用いた攻撃が可能である。今回は、Baby-step Giant-step algorithmも併用して以下のようにソルバーを書いた。
gist.github.com
無事、平文を復号できたことがわかる。