• 締切済み

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と時間を基に、かなり面倒(?)な方法を使っています。 これが何をやっているのか、いまいちわかりません。また、なぜこのような方法にするのか、ご教授のほどお願いいたします。

  • SV576
  • お礼率83% (40/48)
  • Perl
  • 回答数5
  • ありがとう数7

みんなの回答

  • taseki
  • ベストアンサー率66% (155/233)
回答No.5

確かに一見して奇妙ですね。 どう考えても結局randを基にしているのだから、繰り返す意味は無いですよね。 他の方もおっしゃっているように、salt2文字を求めるコード自体を複雑にする効果は特にないと、私も思います(むしろ素直にrandを使ったほうが再現性は低い気がします)。 ご存知かと思いますが、cryptによって生成された暗号化文字の先頭2文字は使われたsaltになります(DESの場合)。なので、実際は暗号化された文字を見ればsaltは判明し、隠そうとする意味はありません。 saltは元の文字列から暗号化する際に56bitの数値を使って演算に加味するというだけの目的ですから、いつも同じものを使うことを避けさえすれば、salt自体を隠す意味はあまりないと思います(厳密には隠せない)。 で、このコードの理由については、あくまでも確信のない推測ですが、成り行きでこうなったとか、「特に意味がない」ということじゃないでしょうか。 良く見てみると、ループが、8文字のsaltに対応させることを容易にさせるためにも見え、MD5のことを考慮してか、あるいはMD5バージョンがあって書き換えたが処理は残っているとか。 そしてまた、timeとの%を取るというのはrandを使わずに乱数を求めるようなケースで昔はたびたび使われた手法でもあり、もともとそのような処理だったのが、randによる方法に改良した、しかしこれもやはり中途半端に残ってしまっている、というようなことではないでしょうか。

SV576
質問者

お礼

ご回答ありがとうございます。 言われてみれば確かにシャッフル?を8回繰り返してますね。これが8文字のsaltに関係する(してた)可能性はありそうですね。 if ($pwd =~ /^\$1\$/)というところは、まさしくMD5用でしょうし。 シャッフルはrandを使っておきながら、そこから1文字取る方法だけ時間などを使っていて、無意味というか意味が解らないですが、、、確かに書き換えを繰り返していくうちにこうなってしまった、と考えると納得できる気がします。 おっしゃるように、どうも特に意味がないというのが正解な気がしました。 その証拠?に、このサイトの最近のプログラムだと、こんな面倒なことしてないんですよね、、先ほど気づきました。そしてこれは古そうです。 本題の疑問だった、saltは単純にrandで良いということが解っただけでも良かったです。

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.4

古いバージョンのperlで動かす事を想定して、乱雑さを増すために、わざと何度もrandをコールする方法をとっているのでは。 最近のperlならあえてsrandを呼ばなくてもすむはずなので。 ソルトの出現確率が一律であるのが最適なので、内部にカウンタをもって0から4095まで順番に払い出すのがベストだったりして。

SV576
質問者

お礼

ご回答ありがとうございます。 なるほどrandの信頼性を補足するようなものですかね、、、。 いろいろなサンプルや信頼できそうな配布プログラムなども見てみましたが、結局どうやら単にrandでよさそうだという気がしてきています。 いまのところ古いバージョンを想定する必要もないので。

  • qtea
  • ベストアンサー率77% (38/49)
回答No.3

Salt文字列を固定ではなく、ランダムにして生成しているのは、Salt文字列と暗号化した文字列の表から、元の文字列を解読するのを難しくする為だと思います。 予め、いくつかのSalt文字列からの表があれば、同じSalt文字列を使用している暗号文字列を解読するのが容易になります。 パスワードをいくつも保存しているファイルがあれば、そのなかのどれかはSalt文字列が同じであるかもしれません。 また、同じSalt文字列が何度も現れていれば、その中で一番多いSalt文字列からその表を作れば、それだけ多くのパスワードが解読できます。 Salt文字列の再現性が低いほうがセキュリティが高いということになります。 なので、CGI RESCUEさんが、複雑な方法で、Salt文字列を生成しているのは、単純な方法でSalt文字列を生成するよりも、再現性が低いと、作成者が考えたからではないでしょうか。 実際に低いのかどうかは別ですが…(変わらないような気もします)

参考URL:
http://www.nurs.or.jp/~ogochan/linux/crypt.html
SV576
質問者

お礼

ご回答ありがとうございます。 saltを再現性の低いものにするためランダムに、というのは理解しております。 >実際に低いのかどうかは別ですが…(変わらないような気もします) そうなんですよ、、、これって、ランダムの文字列を作る方法として、「randを使う方法」と「時間などから演算する方法」とが、混ざっているようなんですよね。 いろいろ他のサンプルもかなり見てみましたが、どうやら単純にrandでよさそう、という気がしてきています。このプログラムだけの、ちょっと不思議な特徴、というところでしょうか。

noname#25358
noname#25358
回答No.2

>それでもやはり解析しにくいようにする必要があるのでしょうか。  サンプルとしての意味もありますからね。 >それほど難解or無意味な処理でもないように思えます  削除しても問題のないロジックが入っているわけではないですから。  複雑なロジックを実装するために必要な処理が入っているわけですから、単純な暗号の場合には、プログラムを複雑化するのも限界があります。 >これでは危険ということですか?  ソースコードを第三者に読まれてしまうケースでは、ロジックを複雑化することは「プログラマーとしてのセキュリティ意識を示す」ことに最大の意義があります。  実際には、やる気のあるハッカーにかかれば解析そのものは簡単なのですから、セキュリティの危険度は同じといえると思います。  でも、ガキのイタズラすら防げないという意味では、単純なソースコードは危険といえるでしょう。

SV576
質問者

補足

ご回答ありがとうございます。 何度もすみません。 どうもやはり私には、暗号化のロジックではなくsaltのロジックを複雑化する効果や意味が良く解らないのが正直なところです。 サンプルであるなら、むしろなおさら(他のサンプルのほとんどがそうであるように)理解しやすいように書くべきな気がするのと、逆にrandと書いたほうが解析できないと思うのですが…。 どうも、このプログラムだけの問題な気がしてきています。 しかし意義などの件は大変参考になりました。ありがとうございます。

noname#25358
noname#25358
回答No.1

>これが何をやっているのか、いまいちわかりません  そう思わせるためにわざと面倒な方法を使います。そのような場合、システム的には必要のないロジックがわんさか入ってたりします。  解析しやすかったら暗号の意味がないですから。

SV576
質問者

お礼

早速のご回答ありがとうございます。 なるほど、解析しにくいようにでしたか。 ただ、これは暗号化そのものではなくて、たった2文字のsaltを求めるだけですが、それでもやはり解析しにくいようにする必要があるのでしょうか。 また、カムフラージュ(?)的なことが目的にしては、それほど難解or無意味な処理でもないように思えます(最終的には2つの乱数を作っているだけ?)。 他の多くのスクリプトでは、質問文に書いたような数行の処理で済ませていますし…、これでは危険ということですか? 重ねてすみませんが、よろしくお願いいたします。

関連するQ&A

  • 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
  • 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スクリプト)

     現在記事削除処理の、キー暗号化と解読について勉強しているんですが、他の方が書いたソースを読んでもさっぱり意味不明です。技術評論社さんのリファレンスを参考にしてるんですが、どうも載っていないワザが使われているらしく・・・。  まずは暗号化処理です(とある有名ソースから抜粋)。 @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
  • 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に関して殆ど解っていないもので、とんちんかんな記述かもしれませんが、ご教授いただけますと幸いです。 宜しくお願いいたします。

  • 型変換??

    int RANDOM_FUNCTION( int n ) { return (int)( rand() / (float)RAND_MAX * n ); } について Q1.この関数は0からn-1までの乱数を作るそうなのですが,何故ですか? 0<=rand()<=RAND_MAX だから0からnまでの乱数ができるような気がするのですが. Q2.RAND_MAXではなく(float)RAND_MAXとキャストしてある意味は何ですか? Q3.srand((unsigned)time(NULL));と srand((unsigned int)time(NULL));では何か違いますか? Q4.  static int first = 0; if (first == 0){ srand((unsigned)time(NULL)); first = 1; } という処理でsrand((unsigned)time(NULL));は最初の一回だけ呼び出されるようになっているようですが,この部分を srand((unsigned)time(NULL)); というように毎回呼び出すようにするとどうなりますか? 一回呼び出すだけで乱数系列の初期値が呼び出される時に変化しているのですか? Q5.この関数とは関係ない質問ですが,例えば a:int型 b:int型 c:double型 d:float型 のとき d = a / b + c という演算は 1 a:int型,b:int型より(a / b)の結果はint型(小数になった場合は小数点以下切り捨て) 2 (a / b):int型,c:double型,int<doubleより (a / b + c)の結果はdouble型 3 d:float型,『=のあるときは左辺の型に合わせる』よりdはfloat型 というように型変換されているという解釈でいいのでしょうか??

  • 乱数で交互に偶数、奇数が、、、。

    C言語で、確率2分の1で0と1を 出そうとして、rand,srand,timeを使って やってみたのですが、ちょうど、0と1が 交互に出てしまいます。何度やっても 変わりません。ただ、1と0が逆になる だけ。こんな感じで0101010101か1010101010 つまり、乱数で奇数と偶数が 交互に発生しているみたいうまくいきません。 なにか、別の方法ありますか? --------------------------------------- srand((unsigned int)time(NULL)); s=rand()%2 これで、やってます。

  • rand関数

    PICをC言語(CCSC)で乱数のプログラムを作りたいと思っています。 乱数ルーチン1 srand(a) i_11=rand() i_12=rand() i_13=rand() . . 乱数ルーチン2 srand(b) i_21=rand() i_22=rand() i_23=rand() . . 乱数ルーチン1をCallした後(電源をOFFしないで)乱数ルーチン2をCallした場合 においてa=bならば i_11,i_12,i_13...i_21,i_22,i_23...は乱数だが i_11=i_21 i_12=i_22 i_13=i_23になってしまう・・・ということでしょうか? もし間違っていたら正解を教えてください。

  • 乱数発生

    #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) {int y, m, l; srand( (unsigned)time( NULL ) ); y=rand() % 2500 + 1600; m=rand() % 12 + 1; l=rand() % 29 + 1; printf("西暦%d年%d月%d日",y,m,l); return(0); }今回は乱数発生でランダムにだされた西暦年月日をつくりましたが、y=rand() % 2500 + 1600; というのがありこれはyという乱数が2500以下1600以上という意味なのですがなぜかプログラムを実行しても3000いくつとか4000いくつなんてのもでてきます。m=rand() % 12 + 1;はちゃんと12以下1以上でできるのですがなぜですか?本当にわかりません。是非だれか教えてください。

  • エクセルで「乱数」を出す@関数は?

    「1-2-3」では、乱数を出す関数は「@INT(@RAND*400)+1」で1~400の間のアットランダムな乱数をさながらサイコロのように出すことが出来るのですが、エクセルではそういう関数があるのでしょうか? 是非教えて下さい。

  • Perl ランダム 0と1 かぶり

    いつもお世話になっております ご教示お願い致します。 □←0 ■←1 とします。 この0と1をランダムに5こでるようにします。 ↓ 例1) □■■□■ 例2) ■■□□□ このようにバラバラに出現させることができました。 しかし、 極稀になのですが、 □□□□□や■■■■■ とすべてかぶることがあります。 この■(1)はすべてかぶってもいいのですが、 □(0)はかぶらないでほしいのです まずそのソースが下記・・・↓ srand(time()^($$ + ($$<<15))); our $val1 = int(rand(2)); our $val2 = int(rand(2)); our $val3 = int(rand(2)); our $val4 = int(rand(2)); our $val5 = int(rand(2)); 0と1が必ずバラバラになるようにするにはどのように するのでしょう?

    • ベストアンサー
    • Perl