パスワードの最良な決め方について(長文)
パスワードを最大限に複雑に決めたいとします。
当然、覚えられないので、適当な言葉で決めて、seedを付けてハッシュ関数へ入力し、出力をそのままパスワードとして使うとします。
(ハッシュ関数の出力は16進数ですが、文字数を少なくしたいので、使える文字を全て使用して、文字へ割り当てます。)
seedは秘匿し、適当な言葉にあたる部分はブログ等に公開でもいいからメモっておくとします。
例えば、この質問サイト(OKWaveからログインしてます)であれば、
OKWavePassword_change#_0 といったような言葉を決めて、SNSのプロフに載っけておくとかです。
実際に使う際には、頭に(どこでもいいのですが)seedを付けて、
myseedOKWavePassword_change#_0
のようにして、ハッシュ値を取り、文字割り当てしてクリップボードへコピーして
パスワード欄に貼り付けるかんじです。
ここからが質問です。
【質問1.ハッシュ関数はどれを使えば良いでしょうか?】
SHA-2シリーズはlength-extension攻撃に弱いので、HMACの形式にして使わなければならず、またその場合、Windowsのコマンドプロンプトで使える手軽な実装が見つからないのもあって(コマンドプロンプトにこだわる訳は要望があれば補足で説明したいと思います)、使用は避けたいです。
そこで、SHA-3シリーズが策定されてるようなので、この中で最大のビット数のものを選べば良いと思っていたのですが、Wikipediaを見たら、SHAKE128、同256というのがあり、読んでみると、
出力長を、任意に設定できる
そうですが、だとすると、SHA-3の最大ビット数(SHA-3 512)と比べて、上述の使い方で考えると、どちらが良いでしょうか?
もしくは、他により良いハッシュ関数がありますか?
というのは、SHA-3 512では(というか、SHAKE以外のSHA-3では)出力長は固定なので、必要であれば(ほぼ全てのケースだと思いますが)
そのパスワードで使用できる最大文字数にしなければならず、
その方法としては、文字割り当てまで終わってから、ただ単に頭から文字数分取るとか、間の文字を抜いて詰めるくらいしか思いつかないので、
それでどの程度、一様性が下がって(偏りが生じて)、危険になるかは、良く分からないのですが、
それであれば、512ビットより落ちる256ビットであるとしても、SHAKEであれば、ハッシュ値が得られた時点で過不足の少ない(0にはならないみたいですが、実装のせい?)情報量に収まっているので扱いやすいこともあり、いいかなと思っているのですが、どうでしょうか?
要するに、512ビット固定長のハッシュ値を文字割り当てしてから(16進表現の時点では難しそうなので)、頭から一定の大きさまで削った場合と、
SHAKE256で最初から過不足の少ないハッシュ値を得て文字割り当てした場合とで、どちらがよりマシかということになると思いますが……
例えば、例としてGmailのパスワードで考えると、確か、ASCII印字文字95種フルフルで使えて最長64文字だったと思いますが、
この場合だと512ビット固定長のがマシになりそうですが……
(512ビットを95進数表現すると78文字(桁)だから、78文字の先頭から文字を取るなり、間を詰めるなりして64文字にするほうが、256ビット分(95進数で39桁)を無理に引き伸ばすより安全そうというのが理由)
↑のようなパスワードを使うことが多ければ、というか多くなくても今後10年くらいは変えたくないので(SHA-1やSHA-2の寿命から;2はまだ死んでませんが)後々の事を考えればSHA-3 512で統一しておいたほうが結局無難でしょうか。
或いは、どっちもダメということもあるのでしょうか……
そもそも、ハッシュ関数を使うという考え方自体がダメだったりするのでしょうか……
【質問2.仮にSHAKE256を使うとすると、出力長はどうやって求めれば良いでしょうか?】
例えば、OKWaveでは、パスワードの文字条件が、
使える文字がa~z, A~Z, 0~9, -, _で、文字数が最大10文字だそうですが、
この場合、パスワードの総パターン数を16進数で表した文字数にすればいいのでしょうか。
具体的には、総パターン数は64の10乗通りで1152921504606846976個、
16進数にすると1000000000000000で16文字で合ってますか?
また、多くの実装では、出力値が0起算のため、例えば今の例だと実際に取り得る値は 0~((64の10乗)-1) の範囲になるかと思いますが、つまり、
000000000000000~FFFFFFFFFFFFFFF
が実際に出てくる値の最小~最大となるため、15文字で設定すれば良いということでしょうか?
【質問3.具体的な例で確認したいのですが?】
SHAKE256で15文字として、seedはなしとすると、
OKWavePassword_change#_0
のハッシュ値は
911C7E7009C307
と出ましたが合ってますか。(HashSum使用←バイト単位でしか設定できないので、8byteだと文字割り当て後、11文字になるパターンが有り得るので7バイトで設定(1byteは16進数2文字))
またこれを64進数に変換すると、
02 17 07 07 57 48 02 28 12 07
になると思いますが合ってますか。
またこれを文字割り当て(ASCII文字コード表の通りの順番で、使用できる文字だけ拾って割り当て)すると、
1G66tk1RB6
となりましたが、合っているでしょうか。一応10文字にはなりましたが。
あと、HashSumがバイト単位の設定なので7バイトにしましたがこれだと9文字になるパターンも有り得ますよね。
その場合は10文字になるまで、入力値のOKWavePassword_change#_0の最後の0を1とか2とかに変えていけばいいかと思ってますが。
まぁそれ用に項目を置いてOKWavePassword_dummy#0_change#_0とかにしてこの場合dummy#の直後の数字を変えるという決めにするとかしとけば、パスワードを今まで何回変更したか知りたい(そんな要望あるのかはともかく)ときにゴッチャにならないで済むけど。
みたいな細かい問題は出てくると思いますが、このように柔軟に対応できると思っていますが、何か他に対応の難しい問題はありそうですか?
【質問4.全体的にどうでしょうか?】
みたいな。
なんか結局、今まで考えていた通りにSHA-3 512でやっとけば良さそうな気がしてきましたが、全体通して総評ください。
以上、よろしくご回答の程、お願いいたします。