パスワード暗号化についての質問

このQ&Aのポイント
  • パスワード暗号化のキー生成方法について質問があります
  • 質問中の暗号化処理について理解できません
  • 暗号化キーに関して疑問があります
回答を見る
  • ベストアンサー

パスワード暗号化について(CGIスクリプト)

 現在記事削除処理の、キー暗号化と解読について勉強しているんですが、他の方が書いたソースを読んでもさっぱり意味不明です。技術評論社さんのリファレンスを参考にしてるんですが、どうも載っていないワザが使われているらしく・・・。  まずは暗号化処理です(とある有名ソースから抜粋)。 @SALT = ('a'..'z', 'A'..'Z', '0'..'9', '.', '/'); srand; $salt = $SALT[int(rand(@SALT))] . $SALT[int(rand(@SALT))]; $encrypt = crypt($password, $salt) || crypt ($password, '$1$' . $salt); 問題は$encryptなんですが、||演算子は、要するに左オペランドの保険みたいなものなんでしょうか?まず、左オペランドが偽になる、ということ自体が分かりません。結果が偽になる、というのは0を返すということでしょうか?  crypt関数が処理を失敗する(?)、ということでも偽になるかもしれないんですが、暗号化処理を失敗などということがあるのでしょうか?  次に、ひとまず左オペランドが偽だった場合ですが、右オペランドに関して、暗号化キーが「$1$xx」の5文字ですよね。暗号化キーは2文字までしか評価されないから、結局これは「$1」と変わらない気がします。というより、まずなぜ「$1$」なんでしょうか?そして、合計5文字の意味は・・・?謎は深まるばかりです。  質問の長さが800文字を超えてしまうので、前半はここで切らせていただきます。  後半は「パスワード解読について(CGIスクリプト)」にて質問させていただいています。  どうかよろしくお願いします。

  • Perl
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

いや、Perlのバージョンによるものではありません。 簡単に言うと、Perlの関数cryptは、内部でOS付属のライブラリcryptを 呼んでいるのです。そしてそれが返すものをそのまま返しているだけ。 例えばFreeBSDではデフォルトでMD5が使われます。しかしこれも 切りかえることができます。詳しくは知りませんがLinuxのいくつかの ディストリビューションでもそうらしいですね。 正確には「OSの種類、バージョン、設定による」のです。 よって、Perlを利用するだけのユーザはどちらが使われているのか 調べてそれ用のコードを書くか、あるいはどちらでも大丈夫な ように書く必要があるわけです。 > DESというアルゴリズムで生成した際には$1$を最初の3文字として解釈してしまうのでは このコードがDESのときどう動作するか?という話ですか? ならば先に左オペランドの「crypt($password, $salt)」が真の値を返しますから 「||」の働きによって後半の'$1$'を含むcryptは実行されず、次の行へ進んでしまい ますので問題ありません。

Yuya_Tachibana
質問者

お礼

 ということは、 $encrypt = crypt($password, $salt) || crypt ($password, '$1$' . $salt); において、MD5というアルゴリズムが使われた場合には左オペランドでエラーを返す(偽になる)ため、||演算子により右オペランドで問題なく真を返し、DESが使われた場合には左オペランドの時点で真を返してくれる、ということだったわけですね。ようやく||の謎が解けました。どうやら、初心者にはレベルが高すぎるソース表記だったようで(汗)。  という感じの考察でした。ここで質問しなかったら、そしてわかりやすい回答が得られなかったらかなりの間分からずじまいになるところでした。  とても助かりました。本当にありがとう御座いました。

その他の回答 (1)

回答No.1

OS(正確にはライブラリですが)によっては、cryptはDESではなくMD5のアルゴ リズムによる暗号を生成します。このとき$salt先頭がアルファベットや数字 の並びだと失敗します。MD5だとsaltには「$1$」で始まる文字列を指定します。 実際にはそのあとに続く文字が使われる、とされています。 そこで、上記のようにすればプロバイダのサーバが使っているアルゴリズム がDESでもMD5でもちゃんと動作するというわけです。

Yuya_Tachibana
質問者

お礼

 なるほど、最初が$1$だったのはライブラリの互換性を考えた設定だったわけですか。ライブラリによってということは、Perlのバージョンによってということでしょうかね?  余談  しかしだとすると、DESというアルゴリズムで生成した際には$1$を最初の3文字として解釈してしまうのではないんでしょうか?

関連するQ&A

  • Prel正規表現で'$1$'.$saltのあたりが理解できない。

    小生Perlを勉強中です。 Perl Codeに以下のようなパスワード暗号処理のサブルーチンが ありましたが、読めません。教えて下さい。 sub encrypt{ local($inpw)=$_[0]; local(@SALT,$salt,$encrypt); @SALT=('a'..'z','A'..'Z','0'..'9','.','\'); srand; $salt=$SALT[int(rand(@SALT)).$SALT[int(rand(@SALT))]; $encrypt=crypt($inpw,$salt)||crypt($inpw,'$1$'.$salt); return $encrypt; } とあります。 特に、下から3行目の($inpw,'$1$'.$salt)が 理解できません。 解説していただければ幸いです。

    • ベストアンサー
    • Perl
  • パスワード解読について(CGIスクリプト)

     「パスワード暗号化について(CGIスクリプト)」の続きとなっています。文字数が800文字を超えてしまったため、分割させていただきました。  続いて解読処理です。こっちは更に謎です。 $salt = $logpassword =~ /^\$1\$(.*)\$/ && $1 || substr($logpassword, 0, 2);  最初は//内の処理です。$1$だけは読めますが、「^」も「(.*)」も最後の$も不明です。「^」はEXORではありませんよね・・・?  次に&&とやはり||です。この辺は「え?ギャグ?」って感じです(まったく分かってません)。  最後にパターン結合演算子ですが・・・。「スカラー式をm//、s///、tr///と結びつける」と言われても何のことやら。大体上の表記ではmもsもtrも使ってないんで・・・。マッチmの略形でしょうか?  ということで長くなってしまいましたが、これらの動作の目的、そして動作原理を教えていただきたく質問させていただきました。  どうかよろしくお願いします。

    • ベストアンサー
    • Perl
  • cryptの動作

    cryptがサーバーによって動作が異なるというのはありうるでしょうか。 cryptが使えないサーバーがあるというのは聞いたことがあるのですが、 if(!&decry("abcd" ,$in{'pass'})){print "不正";} のときに$in{'pass'}に何も入ってない(つまり"")のときになぜか&decryの返り値が1になるサーバーがあるようなのです。しかもおかしなことに、$in{'pass'}になんらかの文字が入っていると"不正"という文字がでるそうなのです。(しかし「abcd」の暗号化文字列がくると不正とは表示されない) しかし私の環境(WinXP【phpdev4 + Active Perl】 と @nifty)では、そんなことはありません。$in{'pass'}=""; でもちゃんと不正と出ます。 私が使っている暗号化と、照会の処理の関数は以下の通りです。 ********************************************** sub encry { srand(); @salts = ( "A".."Z", "a".."z", "0".."9", ".", "/" ); $salt = $salts[int(rand(64))] . $salts[int(rand(64))]; return crypt($_[0], $salt); } sub decry { return($_[1] eq crypt($_[0], $_[1])); } ***********************************************

    • ベストアンサー
    • Perl
  • cryptの使用方法

    パスワードなどを暗号化する際に使用するcrypt関数ですが、最適なsaltの求め方というのはあるのでしょうか。 最も多いと思われるのは、 srand(); @salts = ("A" .. "Z", "a" .. "z", "0" .. "9", ".", "/"); $salt = $salts[int(rand(64))] . $salts[int(rand(64))]; という、普通に乱数を使ったものですが、 結構有名なCGI RESCUEでは、 http://www.rescue.ne.jp/cgi/private2/crypt.cgi ランダムな$keisuと時間を基に、かなり面倒(?)な方法を使っています。 これが何をやっているのか、いまいちわかりません。また、なぜこのような方法にするのか、ご教授のほどお願いいたします。

  • 暗号・復号 cgiスクリプトについて

    こんにちは。 私はcgiスクリプトにて文字を暗号化させたいと思っています。 友人に暗号化復号化スクリプトを書いてもらったのですが どうやって動かすかよくわかりません。 http://www.rescue.ne.jp/cgi/htpasswd/makepwd-des/ 上記のサイトのように出力させたいのですが、スクリプトだけでは私には難しいです。 その友人は海外に行ってしまい連絡が今は取れないんです。 sub enc_string{ my ($key, $string) = @_; my @map = (('A' ... 'Z'), ('a' ... 'z'), ('0' ... '9'), '+', '&'); my @key = unpack('C*', $key); my $str = ''; my @x = map { int(rand(200)) } (0 ... 2); @key = map {$x[$_] ^ $key[$_]} (0 ... 2); while($string ne ''){ my $n = substr($string, 0, 3, ''); my @n = unpack('C3', $n); map{$n[$_] ^= ($key[$_])} (0 ... 2); @key = unpack('C3', $n); @key = map {$x[$_] ^ $key[$_]} (0 ... 2); my $a = $n[0] >> 2; my $b = (($n[0] & 3) << 4) | ($n[1] >> 4); my $c = (($n[1] & 15) << 2) | ($n[2] >> 6); my $d = $n[2] & 63; $str .= $map[$a] . $map[$b] . $map[$c] . $map[$d]; } my $a = $x[0] >> 2; my $b = (($x[0] & 3) << 4) | ($x[1] >> 4); my $c = (($x[1] & 15) << 2) | ($x[2] >> 6); my $d = $x[2] & 63; return $str.'<>'.$map[$a].$map[$b].$map[$c].$map[$d]; } このスクリプトで暗号するようですが、初心者なものでどうやって 手直し?追加すればよいのでしょうか? #!/usr/bin/perlを最初に入れるのはわかります。 あとこのスクリプトの他に復号、MD5にて暗号のスクリプトがあります。 まずは暗号化させてみたいのですが、よろしくお願いします

  • AES暗号にて、AES_set_encrypt_keyで設定されるAES_KEYについて

    VC++2008にてopensslを用いて、AES暗号/復号の機能を作成しています。 AES_set_encrypt_key → ivをコピー → AES_cbc_encrypt(~,AES_ENCRYPT)にて暗号、 AES_set_decrypt_key → ivをコピー → AES_cbc_encrypt(~,AES_DECRYPT)にて復号するコーディングをしました。 (http://d.hatena.ne.jp/hnko/20090302/1235977892のenc_aes128_cbc_test()を参考にしましたので、 一連の流れは、こことほぼ同じです) デバッグしてみると、一見、暗復号が問題なく出来ていたので、 AES_set_encrypt_key関数の第一引数のkey配列の値と、 ivec配列の値を変えて、デバッグしてみたところ、 key配列を変更すると、暗号化後の文字列も変更されますが、 ivec配列を変更しても、暗号後の文字列に変化が有りませんでした。 調べてみたところ、AES_set_encrypt_keyにて返される AES_KEYのroundsの値が常に同じであることが原因と思われますが、 roundsの値が常に一定だと、暗号解読が比較的容易に 出来てしまうと思うのですが、上記で挙げたサイトでの コーディングの他に、何か別にコーディングを足さなければならないのでしょうか? よろしくお願いします。

  • 暗号

    たとえば、a=1,b=2,c=3,・・・というような法則で、何かしら意味のある、十分な量の機密文書を暗号化するとします。 第三者がこの文書を発見し、解読しようとする場合、コンピューターを用いれば解読するのは比較的容易に思われます。 では仮に、完全にランダムな文字10000文字ほどを暗号化した場合、その文字を原文を知らない第三者が複合化するのは可能でしょうか? (解読に用いるコンピューターは無限に早い処理速度を持っているとします。)

  • DB内にMD5でハッシュ化されたパスワードとの照合

    MySQLのDBにMD5でハッシュ化されたパスワードが格納されているのですが、これをPerlのスクリプトで照合したいと思っています。 具体的には、DBに格納されているパスワードを用いて、Perlで作成された会員専用ページなどにログインをするといった感じです。 DBIを用いてDBからの情報を取得することはできたのですが、Perl側での対処がわかりません。 Perl側で入力されたパスワードをハッシュ化して、双方を照合するなどの情報を見たのですが、いまいち解らず認証することができませんでした。 以下にパスワードに関する部分のソースを記載させていただきます。 srand(); @salt = ( "A".."Z", "a".."z", "0".."9", ".", "/" ); $salt = '$1$' . join('', map($salt[int(rand(64))], 1..8)) . '$'; $pass = crypt($in{'pass'}, $salt); crypt($in{'pass'},$ary) eq "$ary") ※$aryはDB内に格納されているパスワードです Perlに関して殆ど解っていないもので、とんちんかんな記述かもしれませんが、ご教授いただけますと幸いです。 宜しくお願いいたします。

  • PerlでLinuxのユーザー認証・管理プログラム

    ブラウザでLinuxのユーザー名とパスワードと入力して、 ユーザー認証してログイン後、Linuxユーザーの パスワードを自分で変更できるプログラムが作りたいのです。 /etc/passwdにパスワードが直接記録されていれば簡単なのでしょうが、 シャドウパスワードなので苦労しています。LinuxはFedora Core3です。 まず、/etc/shadowに記録されているような、 $1$ではじまる暗号化されたシャドウパスワードをPerlで作るには どのようにしたらいいのでしょうか。 pwconvのソースをみたらどんなアルゴリズムかわかると思い、 shadow-utilのSRPMをインストールしてみたりしましたがわかりませんでした。PHPのメーリングリストに $salt = substr(md5(microtime()), 0, 9); return crypt($password, "$1$" . $salt); このようなコードがあったのですが、これでは$saltが毎回 代わってしまい、よくある $salt=substr(暗号化されたパスワード,0,2); if(crypt($pass,$salt) ne 暗号化されたパスワード){ &err("パスワードが違います"); } のような認証ができないのではないかと思いました。 Linuxではどのようなアルゴリズムでシャドウバスワード を作り、パスワードの認証をしているのでしょうか。 つまり、簡単にいうとPerlでシャドウパスワードを使った Linuxユーザーのパスワード認証と パスワード変更ができないか、ということなのです。 また、Perlでシャドウパスワードなど作らなくても system()などを使ってLinuxのコマンドを使えば 各ユーザーの認証やパスワードの変更がブラウザでできるという場合は、 教えていただけないでしょうか。 どうかご教示ください。よろしくお願いします。

  • パスワードのsaltの構築方法

    PHPでパスワードの登録でsaltを使用しようと考えているのですが、ネットで調べても自分の疑問に思っている事が出てきません。 パスワードにsaltという十分な長さ(40文字とか)の文字列を加え、それをmd5などでハッシュ化する・・・と言うことは分かりました。 しかしその実装方法が分かりません。 A.saltはランダム乱数でもいいし、セキュリティは低くなるが固定文字列でもいい。 B.saltは別ファイルに保管(一緒に保管と書いてあるのもありましたが)する。 、というような記事を見かけました。 で、自分はZendFrameworkのマニュアルに沿って考えたのですが、 データベーステーブルにpassword、saltカラムを作成する。 登録時、$_POST['ユーザの入力値']を(ハッシュ化する)passwordカラムに、saltはここでは単純にmt_rand(0,99)としてsaltカラムに登録、とした場合に認証時にはどのようにすればいいのでしょうか? 認証時にユーザの入力したパスワードとデータベースに格納したsaltを結合し、それをmd5()したものと、データベースに格納されているパスワードと同じく格納されたsaltを結合しそれをmd5()したものを比べる ・・・となるとパスワードさえ合って入ればいいので別にsaltは不要なような気がするのでこの実装法は間違っているのかなと思います。 そうではなく、登録時にユーザの入力したパスワードとデータベースに格納したsaltを結合し、それをmd5()したものをpasswordカラム又はsaltカラムに格納する・・・というのも正しいのかな?と思います。 データベースに侵入されればどちらもダメなので、何か別ファイルに保管するのかなとも思いましたが良く分かりません。 登録フォーム => ログインフォームにおいてのsaltの実装法を教えていただけないでしょうか?少し頭がぐちゃぐちゃになり、ちょっと文章がおかしい気もしますがすみません。

    • ベストアンサー
    • PHP