パスワード生成ツールの使い方|暗号学的に安全な乱数とは何か

「ランダムに見える」ことと「予測できない」ことは別物です。本ツールが使う暗号学的乱数の意味、強度の数字の読み方、そして何文字にすればよいのかを、実装と規格で確認できる範囲だけでまとめました。

🔑 パスワード生成を開く文字種・文字数を指定して、暗号学的に安全な乱数で強力なパスワードを生成します。

まずは使い方(3ステップ)

本ツールはページを開いた時点で1本目のパスワードを生成します。初期設定は16文字・大文字・小文字・数字・記号をすべて使う組み合わせで、多くのWebサービスの登録画面をそのまま通せる強さです。設定を変えたいときだけ、次の順で触ってください。

  • 文字数のスライダーを動かす。4文字から128文字まで指定できます。強さに最も効くのはここです。
  • 使う文字種のチェックを外す。大文字・小文字・数字・記号の4種類から選べます。すべて外すと「文字種を1つ以上選択してください。」というエラーになり、生成ボタンは押せません。
  • 必要なら「紛らわしい文字を除外」を入れる。0とO、1とlとI、5とS、8とBの合計9文字が候補から外れます。

「パスワードを生成」を押すたびに新しい1本ができます。結果の下に出る「コピー」でクリップボードへ入り、2秒だけ「コピーしました」と表示が変わります。共有ボタンも置いていますが、共有される文面に含まれるのは文字数と強度だけで、生成したパスワードそのものは絶対に含まれません。

暗号学的に安全な乱数とは何か

プログラムが作る「ランダムな数」には、性質のまったく違う二種類があります。片方は統計的にばらついて見えれば十分なもの、もう片方は過去の出力を全部見せられても次の出力を当てられないことが求められるものです。パスワードに使ってよいのは後者だけで、これを暗号学的に安全な擬似乱数(CSPRNG)と呼びます。

JavaScriptで手軽に使えるMath.randomは前者です。仕様上、実装がどんなアルゴリズムを使ってもよいことになっており、暗号用途に使ってはならない関数として扱われています。実際、多くの実装は内部状態が比較的小さく、出力をいくつか観測すると以後の値を再現できることが知られています。Math.randomでパスワードを作ると、見た目はでたらめでも、生成時刻や出力列から再現される余地が残ります。

本ツールが使うのはWeb Crypto APIのcrypto.getRandomValuesです。こちらは仕様の側で「暗号学的に強い擬似乱数生成器を使わなければならない」と定められており、OSが管理するエントロピー源を種にします。同じ設定で何度生成しても、前の結果から次の結果を推測することはできません。生成処理はすべて端末のブラウザ内で動き、入力した設定も出力されたパスワードも、当サイトのサーバーへ送られることはありません。

乱数から文字を選ぶときに生まれる偏り(モジュロバイアス)

安全な乱数を使っていても、そこから文字を選ぶ手順が雑だと偏りが生まれます。よくある書き方は、0〜255の乱数バイトを文字種の数で割った余りを添字にする方法です。ところが256は多くの場合その数で割り切れません。

初期設定の文字集合は大文字26・小文字26・数字10・記号24で、合計86文字です。0から255までの256個の値を86で割った余りを見ると、余り0〜83は3回ずつ現れるのに対し、余り84と85は2回しか現れません。つまり単純な剰余では、先頭84文字が残り2文字より1.5倍出やすくなります。これがモジュロバイアスです。一発では気づけませんが、パスワードを大量に生成すると分布に癖として残り、総当たりの手間を理論値より下げてしまいます。

本ツールは拒否サンプリングという方法でこれを消しています。86で割り切れる範囲の上限(86×2=172)を求め、172以上のバイト値が出たら採用せずに捨て、次のバイトを引き直します。捨てる確率は約33%ありますが、残った値はすべての文字に完全に均等な確率で対応します。強度の計算式が前提にしている「どの文字も等確率」という状態を、実装の側で本当に成り立たせるための処理です。

強度の「bit」は何を意味しているか

結果の横に「強度: 非常に強い(推定102 bit)」のように表示されます。この数字は、生成手順を知っている攻撃者が総当たりで当てるまでに何通り試す必要があるかを、2の累乗の指数で表したものです。計算は単純で、文字種の数の対数(底2)に文字数を掛け、小数を切り捨てています。86文字から16文字を選ぶ初期設定なら、log2(86)≒6.43に16を掛けて102 bitです。

表示の区分は、40 bit未満が「弱い」、40〜59 bitが「普通」、60〜79 bitが「強い」、80 bit以上が「非常に強い」です。たとえば小文字と数字だけの8文字は、文字集合36文字で41 bitとなり「普通」にしかなりません。同じ8文字でも記号まで入れれば51 bitに上がりますが、それより文字数を12文字に伸ばすほうが効きます(36文字種でも62 bitに届きます)。強さを上げたいときは、覚えにくい記号を足すより文字数を伸ばすほうが常に有利です。

この数字はあくまで生成手順に対する評価であることに注意してください。人が考えたパスワードを本ツールの基準で測ることはできません。「P@ssw0rd!」は9文字で記号も数字も入っていますが、辞書と変換規則の組み合わせで真っ先に試される並びなので、実際の強度は文字数から計算される値とは比べものになりません。ビット数が意味を持つのは、今回のように一様な乱数で選ばれた文字列に対してだけです。

何文字にすればよいか、どう保管するか

本ツールは4文字から128文字までを許容しますが、下限側は「文字数を減らすとどうなるか」を確かめるための範囲だと考えてください。4文字はすべての文字種を使っても25 bitで、現在の計算機なら一瞬で総当たりできます。

実用上の目安は、使い回さない前提で12文字以上、重要な口座やドメイン管理画面のように失うと取り返しがつかないものは20文字以上です。米国のNIST SP 800-63Bのように、利用者が決めるパスワードには最低8文字を求めつつ、64文字以上の長さを受け付けられるようにし、記号の混在といった構成規則や定期変更をむしろ推奨しない、という方向へ整理した規格もあります。長さで稼ぎ、使い回さないことのほうが、複雑さの規則より効くという考え方です。

サービス側が「16文字まで」「記号は使用不可」と制限してくることは今でもよくあります。その場合は文字数のスライダーを上限に合わせ、弾かれる文字種のチェックを外してから生成し直してください。生成前に条件を合わせておけば、登録画面で何度も作り直す手間がなくなります。

生成したパスワードは、記憶せずパスワードマネージャーに保存する前提で使ってください。長くて意味のない文字列は覚えられませんし、覚えられる長さまで縮めると強度が落ちます。メモ帳やスプレッドシートに平文で置く運用は、共有・バックアップ・画面共有のいずれかで漏れます。

このツールでできないこと(先に知っておくと安全です)

本ツールは選んだ文字種から一様に文字を選びます。そのため、まれに「記号にチェックを入れたのに記号が1文字も入っていない」結果が出ます。初期設定の86文字のうち記号以外は62文字なので、16文字すべてが非記号になる確率は(62÷86)を16回掛けた値、およそ0.5%です。これは偏りではなく一様抽選の当然の帰結ですが、登録画面で「記号を1文字以上含めてください」と弾かれたときは、もう一度生成ボタンを押してください。特定の文字種を必ず1文字入れる保証は入れていません。無理に混ぜ込む実装は、その1文字の位置が推測しやすくなり、かえって強度を下げることがあるためです。

また、生成したパスワードが過去の漏えいリストに載っていないかの照合は行いません。照合には入力値を外部サービスへ問い合わせる必要があり、ブラウザ内で完結させるという本サイトの方針と両立しないためです。もっとも、本ツールが作るのは辞書に存在しない乱数列なので、既存の漏えいリストと一致する可能性は実質的にありません。

パスワードの保管・自動入力・同期も本ツールの守備範囲ではありません。生成したその場でコピーし、パスワードマネージャーへ貼り付けてください。ページを閉じれば、生成した文字列はどこにも残りません(クリップボードには残るため、続けて別の文字列をコピーしておくと安全です)。

よくある質問

生成したパスワードはサーバーに送信されますか?

送信されません。乱数の取得も文字の選択もブラウザ内で完結します。共有ボタンを押したときの文面にも、文字数と強度の表示だけが入り、パスワード本体は含まれません。

同じ設定で生成すると、同じパスワードが出ることはありますか?

実用上ありません。crypto.getRandomValuesは呼び出しのたびに独立した値を返します。16文字・86文字種なら組み合わせは2の102乗ほどあり、偶然の一致を心配する必要はありません。

「紛らわしい文字を除外」を入れると弱くなりますか?

わずかに下がります。初期設定では文字集合が86文字から77文字に減り、16文字の強度は102 bitから100 bitになります。紙に書き写す、口頭で伝える、印刷して渡すといった場面では、この2 bitより読み間違いを防ぐ利点のほうが大きくなります。

何文字にすればよいですか?

使い回さない前提で12文字以上、失うと影響が大きいアカウントは20文字以上を目安にしてください。記号を足すより文字数を伸ばすほうが強度は上がります。サービス側に上限があるときは、その上限に合わせて生成してください。

記号を選んだのに記号が入っていません。

選んだ文字種から一様に抽選しているため、確率的に起こります。特定の文字種を必ず含める処理は、その文字の位置が推測されやすくなるため入れていません。条件に合わなければ生成し直してください。

Math.randomで作ったパスワードでは駄目なのですか?

駄目です。Math.randomは暗号用途を想定しておらず、出力の一部から以後の値を再現できる実装が知られています。パスワードのように予測されては困る値には、crypto.getRandomValuesのような暗号学的に安全な乱数を使う必要があります。

この記事を共有

← 使い方ガイドの一覧へ戻る