本文へスキップ

ブラウザツール

Google Authenticator からシークレットキーを取り出す。

Google Authenticator は、端末内のすべてのアカウントが入った QR コードを表示しますが、それを読む手段は用意してくれません。そのコードをスクリーンショットに撮ってここに放り込めば、アカウントごとの base32 シークレットキーと otpauth リンクが手に入ります。

画像がこのタブから出ることはありません。QR コードの読み取り、解析、コードの生成はすべてブラウザの中で行われます。ネットワークを切ったままツールを使ってみれば、それを確かめられます。

ツール

エクスポートコードのスクリーンショットをドロップ

貼り付ける、ファイルを選ぶ、カメラを端末に向ける、どれでもかまいません。

デコードはこのタブの中、手元のマシン上で行われます。だからこそ JavaScript がなければ何も始まりません。代わりに処理できるサーバーはここにはありません。以下ではフォーマットと、ツールがそれをどう扱うかを説明しています。自分で動かしたい方のために、ソースも公開しています。

始める前に

エクスポートコードは、パスワードと同じように扱う。

形式だけの注意書きではありません。エクスポート用の QR コードは多くの人が思っているより危険なもので、作る前に知っておく価値のある点が 3 つあります。

  • コードの写しではなく、鍵そのものがすべて入っています

    コードには、含まれる各アカウントのシークレットキーそのものが入っています。その画像を持っている人は、あなたの端末がなくても、あなたに気づかれることもなく、どの端末からでも有効なコードをいつまでも生成できます。

  • パスワードを変えても無効にはなりません

    新しいパスワードも、新しい端末も、アプリの削除も、書き出されたシークレットを無効にはしません。無効にできるのは、サービスごとに二要素認証をいったんオフにして設定し直すことだけです。これで新しい鍵が発行され、古い鍵は使えなくなります。

  • スクリーンショットはその場では終わりません

    スクリーンショットはカメラロールに残り、そこから写真のバックアップ先にも渡ります。1 年後にそれを見つけた人は、あなたとまったく同じアクセス手段を手にします。信頼できる端末で作業し、終わったら画像を削除してください。「最近削除した項目」からも消してください。

返ってくるもの

すべてのフィールドと、その出どころ。

きちんとやる理由は、デコードしたデータと妥当な既定値を見分けられることにあります。どちらも表示しますが、ラベルで区別しています。

  • シークレットキー

    RFC 4648 の base32、大文字でパディングなし。認証アプリが表示するのとまったく同じ形です。10 バイトの鍵なら 16 文字、20 バイトなら 32 文字になります。認証情報の本体はこれだけで、ほかはすべてそれに付随するメタデータです。

  • 発行元とアカウント

    サービスと、それに属するアカウントです。Google は発行元を専用のフィールドに入れることもあり、「Issuer:account」の形でアカウントのラベルにまとめてしまうこともあるため、どちらも読み取って別々に表示します。

  • アルゴリズム、桁数、種別

    ほぼ必ず SHA-1、6 桁、時間ベースです。サービスが実際に使っているのがそれだからです。エクスポートでどれかが設定されていない場合は慣例上の既定値を使い、そのフィールドはデータではなく既定値として印をつけます。

  • otpauth リンク

    標準の otpauth:// URI です。デコードしたものではなく上のフィールドから組み立て直しているので、他の認証アプリが期待する形と正確に一致します。それぞれに QR コードも用意してあり、別のアプリにそのまま読み取らせられます。

  • 更新間隔の扱いは、正直に。

    どのアカウントも 30 秒と表示されますが、これは何かをデコードした結果ではありません。エクスポートの形式にはシークレット、名前、発行元、アルゴリズム、桁数、種別、カウンターのフィールドはありますが、更新間隔のフィールドはまったくありません。Google Authenticator は書き出すものすべてに 30 秒を使うため、その値を表示し、コードの中に入っていたものと取り違えないよう既定値として印をつけています。

  • カウンターベースのアカウント

    一部のアカウントは時間ベースではなくカウンターベースなので、コードは切り替わりません。カウンターは書き出されたままの値を表示します。扱いには注意してください。コードを使うとサービス側のカウンターが進み、遅れてしまった複製は動かなくなります。

仕組み

5 回のデコードを、順番に行うだけ。

どれも暗号技術ではなく、サーバーも必要ありません。この流れは全部を説明できる程度に短く、説明する価値があります。よくある解説は「このプログラムを 3 つインストールしてください」で終わるからです。

ツールはこの 5 つすべてを自前で実装しており、第三者のコードは使っていません。中でも QR コードの読み取りが、他を大きく引き離して最も大きい部分です。ブラウザが代わりにやってくれないからです。組み込みのバーコード検出機能は Safari と Firefox にないため、デコーダは仕様書から書き起こしています。

  1. 01

    QR コードを読み取る

    画像を白黒に落とし、3 つのコーナーにある位置検出パターンを見つけ、それを通るグリッドを当てはめ(斜めから撮られていれば射影変換で)、すべてのモジュールをサンプリングし、カメラが取りこぼした部分を Reed-Solomon の誤り訂正で修復します。出てくるのは otpauth-migration://offline?data= で始まる文字列です。

  2. 02

    data パラメータをデコードする

    そのパラメータをパーセントデコードすると標準の base64 になり、それをデコードすると数十バイトになります。ここに落とし穴が 1 つあります。URL のクエリパーサで読んではいけません。フォームのデコードが適用されてプラス記号が空白に変わってしまい、標準の base64 はプラス記号を使うからです。

  3. 03

    protocol buffer を解析する

    そのバイト列は、文書化されていない protobuf のメッセージです。繰り返しのアカウントレコード、バージョン、バッチのサイズ、バッチの通し番号、バッチの識別子が入っています。アカウントレコードは 7 つのフィールドを持ちます。シークレットそのもの、名前、発行元、そしてアルゴリズム、桁数、種別、カウンターを表す数値です。

  4. 04

    シークレットを base32 に再エンコードする

    シークレットはバイト列のまま入っています。認証アプリはこれを base32 で表示するため、バイト列を再びエンコードして、別のアプリに手で入力するときの文字列を作ります。

  5. 05

    コードを生成して確かめる

    時間ベースのコードは、その鍵で現在の 30 秒区間を HMAC にかけ、6 桁に切り詰めたものです。HMAC を計算するのはブラウザ自身の暗号機能なので、自作の暗号処理はどこにもありません。生成したコードが端末の表示と一致すれば、取り出しは正しくできています。本当に意味のある確認はそれだけです。

プライバシー

主張は狭く、そして検証できる。

確かめられないプライバシーの主張は宣伝文句です。ですから、正確な主張と、10 秒でそれを確かめる方法を書いておきます。

画像もシークレットも送信されません

ドロップした画像、デコードしたペイロード、シークレットキー、生成したコードは、このタブの中に留まります。これらを扱うコードには fetch、XMLHttpRequest、WebSocket、EventSource、sendBeacon の呼び出しが 1 つもありません。オフライン版ではさらにコンテンツセキュリティポリシーを付けているので、コードの言い分ではなくブラウザがそれを強制します。

自分でやってみる価値のある検証

ネットワークを切って、このページをキャッシュから再読み込みするか、ダウンロードした単一ファイル版を開き、そのままツールを使ってみてください。動きます。サーバーを必要とするものなら動きません。

このページ自体が読み込むもの

大きく言えば嘘になるので、正確に書きます。このページは、自社で運用している小さな解析スクリプトを読み込みます。この解析が記録するのはページのアドレスだけです。このスクリプトはツールには関わらず、あなたが取り出した内容を見ることもできません。それでも気になる場合は、オフライン版には外部への参照が一切ありません。

何も保存しません

クッキーも、ローカルストレージも、セッションストレージも、データベースも、キャッシュもありません。再読み込みすると取り出した内容はすべて失われます。一度は不便ですが、常に正しい挙動です。

消去が実際にしていること

消去すると、シークレットのバイト列をゼロで上書きします。やる価値のある処理ですが、これでシークレットがメモリから消えるわけではありません。JavaScript の文字列は上書きできず、エンジンが私たちにもあなたにも手の届かない複製を保持している可能性があります。完全に終わらせるのはタブを閉じることで、どのページであれ、これ以上を正直に主張することはできません。

公開してあり、読み通せる大きさ

全体が MIT ライセンスの 1 つのパッケージで、実行時の依存関係はありません。背後に監査すべきサプライチェーンがないということです。QR のデコーダ、protobuf のリーダー、base32 と base64 のコーデック、ワンタイムパスワードの関数はすべてこの中にあります。テストは自分自身ではなく、公開されているテストベクタに合わせて固定しています。

コードの出し方

エクスポートコードが隠れている場所。

エクスポートキーでもバックアップでもなく、設定の中にもありません。Google はこれを新しい端末への移行の項目にしまっているので、ほとんどの人は見つけられません。

  1. 01アカウントが入っている端末で Google Authenticator を開きます。
  2. 02メニューを開き、「アカウントを移行」を選びます。
  3. 03「アカウントをエクスポート」を選び、求められたら認証します。
  4. 04必要なアカウントにチェックを入れて進みます。QR コードが表示されます。
  5. 05そのコードをスクリーンショットに撮るか、このツールのカメラを端末に向けます。

コードが複数出てきたとき

アカウントが多いと、Google は一覧を複数の QR コードに分割し、今が何枚目かを示します。すべて撮って、順に追加してください。同じ識別子を共有し、それぞれが自分の通し番号を持っているので、どの順番でも結合され、まだ足りないパートはツールが教えます。別々のエクスポートから出たコードは、結合せずに拒否します。異なるエクスポートのアカウントが重なると、端末上に存在したことのない一覧ができてしまうからです。

写真ではなくスクリーンショットで

スクリーンショットなら一度でデコードできます。画面を写真に撮ると、映り込み、モアレ、遠近のゆがみが加わります。デコーダはどれも処理できますが、どれも必要ありません。他の人の端末を撮る場合は、画面いっぱいにコードを収め、正面から構えてください。

そのあと

シークレットを手に入れたあと、どうするか。

別のアプリに移す

ここではアカウントごとに QR コードを用意しており、形式はどの認証アプリでも読める標準のものなので、別のアプリにそのまま読み取らせられます。base32 の鍵を手で入力する方法もあり、読み取り違いがないことを確かめたい場合はそちらが確実です。

コードを 1 つ、端末と見比べる

この結果に頼る前に、生成されたコードを、同じアカウントについて同じ瞬間に Google Authenticator が表示しているコードと比べてください。一致すれば鍵は正しく、一致しなければ鍵が間違っているので、結果のほかの内容には意味がありません。

パスワードと同じように保管する

シークレットキーの置き場所は、メモや表計算ではなく、パスワード管理ソフトのそのアカウントの項目です。otpauth リンクを貼り付けると、管理ソフト側でコードを生成してくれるものもあります。先に考えておくべき点が 1 つ。パスワードと第二要素の両方を 1 つの管理ソフトが持つと、そこが単一障害点になります。その引き換えを受け入れるかどうかは、人によります。

撮った画像を削除する

「最近削除した項目」からも消し、写真ライブラリがどこかに同期する前に済ませてください。そのうえでツールを消去し、タブを閉じてください。

詳細

細かい仕様。

宣伝を抜きにした、このツールができることとできないこと。ここに並ぶ項目はすべて、パッケージ自身のテストで検証しています。

動作
ブラウザの中だけで動きます。サーバーもアカウントも、インストールするものもありません。
読み取り対象
Google Authenticator のエクスポートコード(otpauth-migration)、および単一アカウントの otpauth コード
入力方法
ドラッグ&ドロップ、貼り付け、ファイル選択、端末のカメラ
出力
base32 のシークレット、発行元、アカウント名、アルゴリズム、桁数、種別、カウンター、otpauth リンク、インポート用 QR コード、現在のコード
通信
ありません。ツールの中に fetch、XMLHttpRequest、WebSocket、EventSource、sendBeacon は 1 つもありません。
保存
ありません。クッキー、ローカルストレージ、セッションストレージ、データベース、キャッシュのいずれも使いません。
オフライン
対応します。単一ファイル版は、ネットワークを切った状態で自分のディスクから動きます。
対応ブラウザ
Chrome、Edge、Firefox、および Safari 16 以降。カメラには安全な接続のページが必要なため、ローカルファイルからは開けない場合があります。
依存関係
実行時はありません。QR のコーデック、protobuf のリーダー、base32 と base64 のコーデック、ワンタイムパスワードの関数はすべてパッケージの中にあります。
ライセンス
MIT

訊いておきたいこと。

エクスポートコードをウェブサイトに入れても安全ですか。
正直に言えば、検証できないページに認証情報を入れるべきではありません。だからこのページは検証できるようにしてあります。何も送信せず、ソースは公開しており、ダウンロードしてネットワークを切ったまま動かせる単一ファイル版もあります。ページそのものを信用したくない場合は、そちらをお使いください。
そちらのサーバーに何か送信されますか。
送信されません。受け取れるものも私たちの側にありません。デコード、解析、コードの生成はすべてブラウザの中で動きます。ブラウザのネットワークパネルを開いたままコードを取り出してみれば、リクエストが 1 件も出ないことがわかります。
インターネット接続なしでも使えますか。
使えます。リポジトリのリリースページから単一の HTML ファイルをダウンロードして開いてください。外部への参照は一切なく、接続を全面的に禁止するコンテンツセキュリティポリシーが入っています。カメラ以外はすべて動きます。ファイルから開いたページにカメラを許可しないブラウザがあるためです。スクリーンショットのドロップや貼り付けは、どこでも動きます。
エクスポートコードが他人の手に渡ったら、どうすれば無効にできますか。
シークレットキーだけを無効にすることはできません。該当するサービスで二要素認証をオフにして、もう一度設定してください。これで新しい鍵が発行され、古い鍵は使えなくなります。パスワードを変えてもこうはなりませんし、アプリの削除や端末の初期化でも同じです。
Google から QR コードが複数出てきました。どうすればいいですか。
すべて撮って、1 枚ずつ追加してください。同じバッチ識別子を共有し、それぞれが自分の通し番号を持っているので、どの順番でも結合され、まだ足りないパートはツールが教えます。すでに追加したものをもう一度追加しても問題ありません。別々のエクスポートから出たコードは、結合せずに拒否します。結合した一覧は、端末上に存在したことのないものになるからです。
どのアカウントも 30 秒と表示されるのはなぜですか。
エクスポートの形式に更新間隔のフィールドがなく、Google Authenticator はすべてに 30 秒を使っているからです。値としては正しいものの、何かをデコードした結果ではないため、データとして示すのではなく既定値として印をつけています。もしサービスが別の間隔を使っていても、このアプリのエクスポートからはそれがわかりません。
アカウントの 1 つで、コードが切り替わりません。
それはカウンターベースのアカウントで、切り替わらないのが本来の動きです。カウンターは書き出されたままの値を表示します。扱いには注意してください。コードを使うとサービス側のカウンターが進むため、遅れてしまった複製は受け付けられなくなります。
対応しているアルゴリズムを教えてください。
SHA-1、SHA-256、SHA-512 で、いずれもブラウザ自身の暗号機能を使います。MD5 はこの形式のアルゴリズム一覧に載っていますが、ブラウザが計算できないためコードは生成しません。シークレットとそれ以外のパラメータは正しく返します。実際のところ、サービスが使うのは SHA-1 と 6 桁で、Google Authenticator はそれ以外を無視します。
カメラが動きません。
カメラには安全な接続のページが必要なので、素の http では開かず、file のアドレスからも開かないことがあります。一度拒否すると記憶される傾向があるため、ブラウザのサイト設定を確認してください。カメラの状態に関わらず、スクリーンショットのドロップや貼り付けはどこでも動きます。
iPhone の写真が開けません。
iPhone の写真は HEIC で、Safari 以外のブラウザはこれをデコードしません。写真ではなくスクリーンショットを撮るか、ファイルを PNG か JPEG に変換してください。いずれにしてもスクリーンショットのほうが良い入力です。映り込みも遠近のゆがみも入らないからです。
これを別の認証アプリに移せますか。
移せます。アカウントごとに標準の otpauth 形式の QR コードがあり、これはどの認証アプリでも読み取れます。base32 の鍵を手で入力してもかまいません。端末から何かを削除する前に、生成されたコードを 1 つ端末と見比べてください。
zbarimg と Go のプログラムで同じことをするのを見たことがあります。
それも同じ 3 回のデコードで、手前に 3 つのインストールが並んでいるだけです。QR コードを読み、data パラメータを base64 でデコードし、protobuf を解析する。ここではその全部をページの中で行います。スクリプトから使いたい場合のために、背後のパッケージも公開しています。これらのツールをラップしているわけではありません。QR のデコーダと protobuf のリーダーは、それぞれの仕様書から書き起こしています。

持っていくのも、確かめるのも、あなたの自由。

実行時の依存関係がない、MIT ライセンスの 1 つのパッケージです。読む、フォークする、オフラインで動かす、あるいはここで使うだけでもかまいません。

ソースコードを見る