また、この形式のパスワードは Apache の htpasswd でも利用されることがありますが、 主に Linux や FreeBSD 等のオープンソース系のどのソフトでどのような暗号が使われているのかをまとめている書籍やホームページなどはありますでしょうか?
PHP の crypt(PHP: crypt - Manual)は、おそらく、glibc の crypt 関数に依存する物だと思います。
md5("plain_text") で MD5 ハッシュを発生させることもできますが、これらの間で「salt が要不要の違いがある」「出力されたハッシュの長さの違いがある」という違いがあったため、
「長さ」の違いは、文字表現にした時の違いだと思います。
そもそも、MD5 の値は 128 bit の値なので、16 バイトのバイナリ値です。これを文字に直す時に、md5() では 16 進数表記に、crypt で生成された文字列のハッシュ値部分は、Base64 になっていると思います。
16 進数表記であれば、1 バイト 2 文字なので、32 文字。Base64 だと 6 bit で一文字なので、128 / 6 = 21.333... で 22 文字になります。
このページが参考になります。
http://oku.edu.mie-u.ac.jp/~okumura/c/auth.html
少し古い方式ですと以下のページが参考になります。
http://www.icepp.s.u-tokyo.ac.jp/~sensha/software/Linux/JF/Shado...
それと格納されているのは単方向変換なのでいわゆる「暗号」とはちょっと違います。復号できないですから。
いずれにせよ、LinuxなどUnix系OSではパスワードなど復号する必要の無いものの保存にはcrypt関数が良く使われています。自前で下手に実装するよりはずっといいですから。
回答ありがとうございます。すみません、暗号化とハッシュ計算はごちゃごちゃに発言してしまっていますね。
passwd や shadow の仕組みについてはわかっているのですが、ここで用いられている crypt の MD5 についての詳細が書かれたページの情報が欲しい感じです。参考サイトにもある "$1$wpkFeWyW$dRnpRo1XDyGJQkc1IM3CT1" というハッシュ値は salt 付き 34 Byte(salt を抜くと 22 Byte)ですが、 MD5 は salt 無し 32 Byte のハッシュを出力という認識でしたので、この crypt の MD5 出力とは一体なんぞや?という話なのです。
MD5 の亜種には salt を利用する SMD5 というものがあるようですが、
ちょっと、この辺に混乱があるようなので、補足しておきます。
MD5 は t-wata さんが指摘されているように「暗号」とは違い、変換の結果から元に戻せない「一方向関数」、または、「ハッシュ関数」と呼ばれるものの一つで、その他に有名なところとしては SHA というものもあります。
で、SMD5 は、結果として保存しているデータが、元のデータにソルトの値を付加したものを入力として、MD5 の値を保存したものを呼びます。もし、ハッシュ関数に SHA を使えば、SSHA と呼ばれます。先頭の S は「Salted」の略です。
/etc/shadow の書式に関しては、下記のページが参考になります。
Shadow password - Wikipedia, the free encyclopedia
英語ですが、真ん中あたりに、$1$ が MD5 で、$2$ が Blowfish(blowfish 自体はハッシュ関数では無いですが、入力をキーとして特定の文字列を blowfish で暗号化した結果をハッシュ値として扱います) で、$5$ が SHA-256 で、といった説明が出ています。
/etc/shadow ファイルのパスワードフィールドの書式としては、'$' で始まる3つのフィールドがあって、先頭がハッシュ関数の種類、2つ目がソルトの値を表し、3つ目が「パスワード文字列に、2つ目にあるソルト値として付加したものを、1つ目のフィールドに指定されたハッシュ関数で計算した結果」という意味になります。
なので、パスワードフィールドの3つ目の値は、
または、
という事になります。
SMD5 と言っても、MD5 というハッシュ値を求める処理自体には違いがなく、入力値にソルトを付加することで、Rainbow Table のような「予め、ハッシュ値を計算したデータベースを作って、元のパスワードを求める」という攻撃に対抗している、ということになります。
手前味噌ですが、OpenLDAP で使える「SSHA」に関して、その計算手順を追ってみた事があります。参考になれば幸いです。
詳細な回答ありがとうございます。手元の Ubuntu では SHA-512 を表す "$6$" が使われていますね。参考になります。参考サイトも読ませていただきますね。
t-wara さんの返信にも書いたのですが、うーむ、すみません、質問が悪かったですね。もっとも端的に言うと、PHP では crypt("plain_text", "$1$salt") で MD5 ハッシュを発生させることも、md5("plain_text") で MD5 ハッシュを発生させることもできますが、これらの間で「salt が要不要の違いがある」「出力されたハッシュの長さの違いがある」という違いがあったため、これらの関係性が知りたかったという感じです。crypt と md5 関数で同じ平文から同じ MD5 ハッシュを出力を得ることはできるでしょうか?
PHP の crypt(PHP: crypt - Manual)は、おそらく、glibc の crypt 関数に依存する物だと思います。
md5("plain_text") で MD5 ハッシュを発生させることもできますが、これらの間で「salt が要不要の違いがある」「出力されたハッシュの長さの違いがある」という違いがあったため、
「長さ」の違いは、文字表現にした時の違いだと思います。
そもそも、MD5 の値は 128 bit の値なので、16 バイトのバイナリ値です。これを文字に直す時に、md5() では 16 進数表記に、crypt で生成された文字列のハッシュ値部分は、Base64 になっていると思います。
16 進数表記であれば、1 バイト 2 文字なので、32 文字。Base64 だと 6 bit で一文字なので、128 / 6 = 21.333... で 22 文字になります。
なるほど、出力データが 32 バイト文字列であると勝手に頭の中で固定化されてしまっていました。MD5 は 128 bit とは定義されていますが、文字列表現の形式までは定義してなかったのですね。データ長も計算どおりということで、今ずっともやもやしたものがすっきりしました。
二度もお付き合い頂き、本当にありがとうございました!
まず、MD5ですが、これはハッシュ値の長さは固定で128bit(=16byte)です。
PHPはじめ良くあるのは、この128bitを16進数表記(2^4)の32文字に変換します(4bit*32文字)。
http://www.php.net/manual/en/function.crypt.php
一方、crypt関数ですが、こちらは128bitをBase64風に64文字(2^6)を使用して22文字に変換します(6bit*22文字、4bitはあまり)。
また、crypt関数はパスワードを安全に保管するための関数であるので、互換性や安全性が考えられて作られています。
http://www.unixuser.org/~haruyama/security/SinSec20101026/build/...
これの「1.1.5. 実際の処理」「1.1.6. stretchとは」あたりにあります。
このため「単純にmd5関数で変換しただけ」というわけではありませんが、使っている関数(または計算方法)は同じですから、同じようにすれば同じ平文から同じ文字列が得られます(そうでないと困ります)。
実際の方法は下記です。16年前から方法は変わっていません。変えるとログインできなくなってしまいますから。
http://svn.freebsd.org/viewvc/base/head/lib/libcrypt/crypt.c?rev...
以降、*BSDやlinuxではこれが採用されていき、時代と共に拡張されて今に至ります。
やはりハッシュの長さは固定だったのですね。具体的な処理内容に興味があったのですが、ずばり crypt 関数の中身に関する資料ありがとうございました。勉強に crypt() 関数を md5() 関数で再現してみようかな、とも思いましたが思いのほか複雑ですね。
なんにせよ、この資料があれば crypt の MD5 に関する脳内の関連付けが完全に把握できました!回答ありがとうございました。
なるほど、出力データが 32 バイト文字列であると勝手に頭の中で固定化されてしまっていました。MD5 は 128 bit とは定義されていますが、文字列表現の形式までは定義してなかったのですね。データ長も計算どおりということで、今ずっともやもやしたものがすっきりしました。
二度もお付き合い頂き、本当にありがとうございました!