WPA2-PSKの鍵共有プロセス
「wpa 解析」とか「wpa2 解析」とかの検索ワード経由での本ブログの記事へのアクセスが増えています(2020/08/10時点).該当記事では単純にAircrack-ngを用いてパスワード解析を行う手順を示しただけで,肝心のプログラムがどのように動いているか等の情報はほとんど書きませんでした.これではScript kiddieでさえないので,WPA2-PSKの認証プロセスを調べ,Aircrack-ngと似たような働きをするプログラムをC言語で書いてみました.本稿はその前半です.
大まかな流れ
WPA2-PSKにおける認証を簡単に表すとこのようになります.
- アクセスポイント(以下AP)とクライアント(以下CL)間で,SSIDとお互いのMACアドレスを共有する
- APは共有された情報と設定されたWPAキー(パスワード)から一時的な鍵を生成する
- CLのユーザはパスワードを入力し,それと共有情報から一時的な鍵を生成する
- 4-Way Handshakeによってユーザが入力したパスワードが正しいか判定し暗号鍵を共有する
- 暗号化された通信を開始する
本稿では,4-Way Handshakeと各鍵の生成方法について書いていきます.
4-Way Handshake
4-Way Handshakeとは,4つのパケットをやり取りすることで,暗号化通信に用いるPTKとGTKという2つの鍵を共有する手順のことです.GTKはそのAPに対する接続すべてで同じものを用いますが,PTKはCLごとに異なり,さらにPTKが経路上を流れることはありません.WPA2ではPTKやGTKを定期的に更新することで安全性を高めています.
4-Way Handshakeの挙動を以下に示します.ユーザが接続したいSSIDを選んでパスワードを入力し,「接続」ボタンを押すとこのようなやり取りがなされるわけです.
鍵やパスワードのデータが直接経路上でやり取りされることがないため,チャレンジ・レスポンス方式による認証であると分かります.なお,各パラメータの生成タイミングは実装により異なることがあります.
前提として,CLのユーザは正しいパスワードを入力したものであるとします.APとCLはそれぞれパスワードとSSIDを用いてPSKと呼ばれる鍵を生成します.WPA2-PSKの場合,PSKはPMKと同一であるため,これでPMKの共有が完了したことになります.
PMKを生成したあと,APは疑似乱数を用いてナンスと呼ばれる256bitのデータを生成します(図におけるナンスA).このナンスAを4-Way Handshakeのメッセージ1としてCLに送ります(#1).
同時にCLもナンスを生成します(ナンスS).CLはPMK,APおよびCLのMACアドレス,生成したナンスS,そしてAPから送られてきたナンスAを用いて,PTKを生成します.そしてナンスSをメッセージ2としてAPに送ります(#2).
CLからナンスSを受け取ったAPも同様の手順でPTKを生成します.APはGTKを暗号化し,さらに暗号化したGTKとPTKを用いてMICという値を作成し,暗号化されたGTKとMICをメッセージ3としてCLに送ります(#3).
メッセージ3を受領したCLは暗号化されたGTKを受け取り,自らのPTKを用いてMICを計算します.この結果と受け取ったMICが同じであることを確認し,APにACKを送ります(#4).
以上の手順によってPTKとGTKが共有され暗号化通信を開始する準備が完了します.
鍵の生成方法
PMK
PMKはPairwise Master Keyの略であり,鍵長は256bit(32バイト)です.WPA2-PSKでは後に示すPSKと同じ値になります.
PSK
PSKはPre-Shared Keyの略で,事前共有鍵という意味です.パスワードとSSIDから一意に求められます.計算手順の概略図を示します.
まず,パスワードをメッセージ,SSIDの末尾に整数(int型,4バイト)の「1」を付加したものをソルトとして,疑似乱数関数(PRF: Pseudo-Random Function)であるHMAC-SHA-1による160bitのMAC値を求めます.以降はパスワードをメッセージ,前段で求めたMAC値をソルトとしてさらにMAC値を求めていき,これを4096段まで行います.
全段の出力のXOR(排他的論理和)をとったものがPSKの先頭160bitとなります.
続いて,SSIDの末尾に付加する整数を「2」とし,同様に全4096段の出力のXORをとったものを,PSKの161bit目におきます.この時点でPSKのデータは320bitとなっており,このうちの先頭256bitが実際のPSKとなります.
この一連の操作はPBKDF2(Password-Based Key Derivation Function 2)という名前の鍵導出関数です.SSIDが固定の場合でも,パスワード1パターンに対してHMAC-SHA-1を8192回も実行する必要があります.これによって,総当たり攻撃に対する耐性を高めているものと考えられます.
PTK
PTKはPairwise Transient Keyの略で,鍵長は640bit(80バイト)です.PTKを求めるには,まずPKEというデータを用意する必要があります.
PKEは800bit(100バイト)のデータで,以下のような構造です.
まず,先頭に文字列として「Pairwise key expansion」を並べます.char型配列に1文字ずつ並ぶ感覚です.これで23バイト目までが埋まります(null文字'\0'もカウントします).
次に,APとCLのMACアドレスを並べます.2つのMACアドレスを比較し(これにはmemcmp()関数を用います),小さい方を先に,大きい方を後に並べます.MACアドレスは1つ6バイトであるため,この操作によって35バイト目までが埋まります.
続いて,APとCLがそれぞれ生成したナンスを並べます.これもMACアドレスと同様に大きさを比較し小さい方から並べていきます.ナンスは1つ32バイトなので,これで99バイトまで埋まります.
最後の1バイトは8bitの符号なし整数を付加します.
さて,PKEを構築したのでPTKの計算手順を示します.
PMKをメッセージ,PKEをソルトとして,HMAC-SHA-1によるMAC値を4回求め,それを並べたものがPTKになります.なお,MAC値を計算する際にはPKE末尾の8bit符号なし整数の値を1から4まで変化させます.
鍵計算全体のフロー
鍵を導出する手順全体は以下のようになります.
おわり
4-Way Handshakeと認証に用いるいくつかの鍵の計算方法について書きました.次回は,これらの情報をもとに,パケットキャプチャファイルとパスワード辞書からWi-Fiのパスワードを調べるプログラムについて書こうと思います.