Android / 実践ケーススタディ / 読了目安:18分
Aegis:なぜ60秒で認証コードが変わる?
認証アプリの見た目は6桁の数字とタイマーです。REA による Aegis の調査記録をたどり、時刻を自分で操作できる小さな実装を試します。
このページの内容
時刻に基づくコード計算を一つ読み解いてブラウザーに再実装し、30秒の区間が切り替わる境界を検証します。
始める前にデモはすぐに使えます。APK の調査も行う場合は、REA、Aegis v3.4.3、完全な JDK 17+、次のガイドで説明する jadx プロバイダーが必要です: Android ガイド。
01. 59秒から60秒へ進める
下の二つの時刻ボタンを押してください。固定の公開テストキーを使うと、59秒のコードは 287082、60秒のコードは 359152になります。30秒に戻すと最初のコードが戻ります。30秒と59秒は同じ時間区間に属するためです。
公開テストキー · SHA-1 · 6桁
Unix 時刻 59秒 カウンター 1
59 ÷ 30 → カウンターは1。60秒になると2になります。
RFC 6238 の公開テストキーを使った独自の学習用実装です。アカウントの秘密鍵や、ブラウザーからの REA 呼び出しは使用しません。
ここでの数字は Unix エポックからの経過秒数で、時計に表示される秒ではありません。デモは標準 TOTP を実装し、次の公開 ASCII キーを使います: 12345678901234567890。Aegis の保管庫を読み込んだり、アカウントの秘密鍵を使ったりはしません。
02. APK 内の時刻ベースのメソッドを探す
REA の公式レポート は、REA 6.1.0 で Aegis v3.4.3 を調査した記録です。同じ手順をたどるには、 該当リリースを入手し、ハッシュを記録して TOTP クラスを検索します。以下のコマンドは REA 6.4.0 を使います。
npx -y [email protected] inspect-android-package "/absolute/path/aegis-v3.4.3.apk" --json
npx -y [email protected] search-android-classes "/absolute/path/aegis-v3.4.3.apk" Totp --json返されたクラス名を正確に使い、そのメンバーを確認します。時刻を直接指定できる、次のメソッドのタイムスタンプ付きオーバーロードが役立ちます: getOtp。同名の最初のメソッドが正しいと決め付けず、一覧から適切なオーバーロードを選んでください。
REA で /absolute/path/aegis-v3.4.3.apk の TotpInfo クラスを調べてください。タイムスタンプを受け取る getOtp オーバーロードを選び、カウンターのエンコード、HMAC、切り詰め、10進数への整形まで呼び出しをたどってください。既定の周期、ハッシュ、桁数を特定し、調べた各メソッドを示してください。既定値とアカウント別設定を区別し、APK は実行しないでください。03. 計算の全体像を読み解く
30で割る処理を見つけるのは出発点にすぎません。元の報告は五つの段階をつないでいます。時刻を切り捨ててカウンターに変換し、8バイトのビッグエンディアンで表現し、鍵を使って HMAC を計算し、ハッシュから正の31ビット値を取り出し、先頭のゼロを残して6桁にします。
見慣れたソース名に頼らず、実際に返されたメソッド呼び出しをたどります。調査対象の版では最適化により生成用ヘルパーが次の場所に配置されていました: kotlin.ExceptionsKt。報告では、既定の SHA-1、6桁、30秒と、アカウント固有の設定も区別しています。
04. ルールを再実装し、境界をテストする
読み解いた動作を独立して実装し、公開テストベクトルで確認します。時刻境界の直前と直後、先頭がゼロになる結果、6桁と8桁の出力をテストしてください。この例では隣り合う区間のコードが異なりますが、数学的に必ず異なるわけではありません。
読み解いた動作に基づく小さな独立 TOTP 実装を書いてください。RFC 6238 の公開テストキーのみを使い、SHA-1 の六つの参照時刻すべてについて、8桁の値と6桁にした剰余を検証してください。29/30秒と59/60秒の境界をテストし、先頭のゼロを保持してください。調査したメソッドとの差を説明し、保管庫や Android アプリ全体の再実装とは主張しないでください。| Unix 時刻 | カウンター | 6桁の結果 | 検証する内容 |
|---|---|---|---|
| 29 | 0 | 755224 | 最初の区間の終端 |
| 30 | 1 | 287082 | 境界を通過 |
| 59 | 1 | 287082 | 同じ時間区間 |
| 60 | 2 | 359152 | 次のカウンター値 |
| 1111111109 | 37037036 | 081804 | 先頭のゼロを保持 |
05. 「133件の検証」が示す範囲
元プロジェクトは、選択した逆コンパイル済みメソッドから組み立てた JVM 検証環境と独立した再実装で、133件の入力が一致したと報告しています。元の APK は起動していません。これは対象の計算を裏付けるもので、アプリ全体の同等性は示しません。
当サイトでは別途 WebCrypto デモを書き、公開された六つの SHA-1 ベクトルを2種類の桁数で確認しました。また、0〜120秒のすべての整数秒を別の Node HMAC 実装と比較しています。元の APK 調査や Java 検証環境の実行は繰り返していません。
出典: REA の Aegis 検証レポート · RFC 6238 のテストベクトル。デモと解説は独自制作です。Aegis アプリのソースコードは再配布していません。