追記:6とbも間違うぞという指摘があったので、修正します。
ユーザ名やパスワードは、時として「手で入力する」ことを必要とします。もちろん、コピペもあるんですが、手入力を必要にすることで、意図的にセキュリティレベルを高めることもあるかもしれません。そのとき、印刷状況によって、数字の「1」と「小文字のL」の見分けがつかなかったりということが発生します。もちろん、フォントの工夫と、アルファベットおよび数字などの使用している文字をサンプルとして印刷するということで対処する場合もあるかもしれません。
ここで、いっそのこと、間違えやすい文字列はもともと含めないでアカウントやパスワードを作るのがいいのではないかとも言えます。とはいえ、「間違いやすい」というのもちょっと曖昧な定義です。ご意見をいただければと思います。なお、ここでは記号類、全角文字は排除されているものとします。
数字+アルファベット大文字
- 0 O(見栄えが似ている)
- 1 I(見栄えが似ている)
- Q 9(発音が似ている)
数字+アルファベット大文字小文字
- 1 l i j(見栄えが似ている)
- 6 b(見栄えが似ている)
- 0 O o(見栄えが似ている)
- Q 9 q(発音が似ている)
- C c(見栄えが似ている)
- K k(見栄えが似ている)
- S s(見栄えが似ている)
- V v(見栄えが似ている)
- W w(見栄えが似ている)
- X x(見栄えが似ている)
- Z z(見栄えが似ている)
Zとzを間違えるかというと、微妙かもしれませんが、ありそうなことを排除することを考えています。フォントに寄っては、Zとzは区別しずらい、あるいは間違えやすいことはあるだろうということです。それでも、Tとtは区別はつくだろうとうことでリストには入れていません。
Qと9の区別は、日本語だけだろうということもあります。また、大文字と小文字の違いがある場合には発音だけでは判定できません。音声でコードを伝える必要がある場合は、アルファベットは大文字か小文字かのいずれかだけにしないといけないでしょう。どちらを使うかは、使用するシステムに依存すると思います。
上記のルールを適用して間違えやすい文字列を排除すると、使える文字列はこうなります。
数字+アルファベット大文字(30文字)
- 2345678ABCDEFGHJKLMNPRSTUVWXYZ
数字+アルファベット大文字小文字(3735文字)
- 234578ABDEFGHJLMNPRTUYadefghmnprtuy
以前、クーポンコードのようなものを考えたとき、その手入力が必要としたらどうなるかを考えました。その仕様がどうだったかはどうでもいいので、現状での記述に揃えます。ただ、ランダムに作るというよりも、生成した乱数をビットに分離すれば、変換はやりやすいと考えました。つまり、base64の原理です。4ビット16文字なら16進表現の方がいいでしょう。6ビット64文字にするには、上記のいずれのパターンも足りません。そこで、5ビット32文字で考えます。「数字+アルファベット大文字小文字」をもとに、さらに微妙に間違いが発生しないかと考えられる以下の53文字を排除するとします。
- m n
r(お互いにデザインが類似している) - u
y(大文字のデザインにそこそこ近い)
こうして残ったのが以下の32文字、つまり5ビットです。5ビット分ずつ、以下の文字列に置き換えれば、乱数からそのエンコード表現ができあがり、手入力時に間違いやすい文字列が排除されているということになります。
数字+アルファベット大文字小文字(32文字)
- 234578ABDEFGHJLMNPRTUYadefghprty
こんなことまで考えて、クーポンシステムを作ったのに、全然使われなかった…。まあ、それは仕方ないとして、別件でランダムパスワードの生成が必要になったので、思い出してブログにまとめました。