ハッシュを使った擬似乱数

このQ&Aのポイント
  • ハッシュを使って予測不能な擬似乱数列を生成する方法について説明します。
  • 鍵(種)のサイズや変化の方法について考える必要があります。
  • bit数を大きくしなければならないが、1加算したときの変化が小さいことが課題です。
回答を見る
  • ベストアンサー

ハッシュを使った擬似乱数

予測不能な擬似乱数列を生成する際に、よく一方向ハッシュの性質を利用する 場合があります。一方向ハッシュの生成源として内部状態が与えられますが、 内部状態のbitサイズはどの程度にしたらよいでしょうか?   [種(カウンタの初期値)]        |        |        ↓ ┌→[内部状態(カウンタ)]―┬―→(一方向ハッシュ)――→擬似乱数列 |                 | |                 ↓ |               [1増加] |                 | └―――――――――――┘ ※ 暗号技術入門 秘密の国のアリス 結城 浩 著      ――第12章 乱数 Fig.12.5 より 極端な例として鍵(種)のサイズを32bit(C言語でunsigned long型)、値を0とします。 |0000 0000|0000 0000|0000 0000|0000 0000| 上記の値でハッシュ値を取ります。ハッシュアルゴリズムがSHA1の場合、 以下のような値が得られます(と思います)。 a = -1099956234 b = -343932961 c = -1287651379 d = -84150665 e = -1099170433 これらの値から鍵の値を得ることは困難なので、ハッシュ値によって生成された 擬似乱数は予測不能であるといえます。また、鍵の値を1だけ加算させて次の擬似乱数 を生成します。一般的にこのようにして乱数列は生成されます。 上記の例では32bitのとり得る値は0~4294967295です。鍵の値を一つずつ試し ていけば、それほど時間をかけることなく乱数の予測不能性は破られてしまいます。 ここで鍵の値を256bitとしました。 |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| しかしこれだと1加算しただけではビット全体に対して変化が少なすぎます。 |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0001|← 2005年に中国の大学の研究チームによってSHA1の弱衝突耐性が破られてしまいました。 現段階ではSHA1に変わる新しいアルゴリズムは発見されていません。(SHA2が作られましたが、 これはSHA1のbit数を拡張しただけで基本設計は変わっていません)なのでハッシュ値を 生成させる値もなるべく変化に富んだ値を与えることが推奨されています。 まとめると、   ・鍵(種)を総当り攻撃されないようにbit数を大きくしなけらばならない。   ・bit数を大きくすると1加算したときに変化が小さすぎる。   ・最初の図の手法は同記の文献に書いてあったもので、なるべく変えたくない。    (実際に使われる手法はある程度保障されているから) の制約があります。なので”bit数をどの程度にしたら適当か???”というのが質問です。 また、これらの問題を打開する方法もあればよいのですが、、、

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

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

まず、SHA1の安全性については「(弱衝突ではなく)強衝突に対する脆弱性が見つかった」というもので、m1≠m2かつSHA-1(m1)=SHA-1(m2)となるm1とm2の組が2^(-80)よりも高い確率で見つかることが理論的に示されました。ただし、現時点でこの条件を満たすm1とm2が見つかったわけではありません。また、SHA2が同じような脆弱性の危険性が言われたりしますが、現時点では実際に脆弱性が見つかったわけではありません。 さらにSHA1に変わるアルゴリズムとして、NISTでSHA3コンペティションというのが開催されており、様々なアルゴリズムが提案されております。 さて、ご質問の「bit数をどの程度にしたら適当か?」という問いに対する答えとしては「一方向性ハッシュ関数の脆弱性が見つかるかどうかに依存するが、今のところ脆弱性が見つかっていないのであれば共通鍵暗号における鍵の全数探索の耐性と同等(今なら128ビット)以上であれば」となるのかなと思います。 「鍵(種)を総当り攻撃されないようにbit数を大きくしなけらばならない」はその通りですが、「bit数を大きくすると1加算したときに変化が小さすぎる」については、安全な一方向性ハッシュ関数であればここは問題にはなりません。なぜならば、もしある特定のビットを固定した複数のメッセージを一方向性ハッシュ関数に入力し、その出力に相関があるのであれば原像攻撃に弱いことになる(すなわち脆弱性がある)ことから、安全な一方向性ハッシュ関数であれば当然その脆弱性は(見つかって)ないということになるからです。 よって、あとは一方向性ハッシュ関数しだいということになります。そして、その脆弱性が見つけられていないのであれば、あとは入力値である鍵(種)の全数探索の耐性があればよく、共通鍵暗号の鍵長と同じ考えになるかと思います。

kaz161573
質問者

お礼

ありがとうございます。確かに現時点でSHA1のアルゴリズムを使用している例は たくさんあるようですね。SHA1の強衝突(質問の文章で間違えてましたね^^;) に対する脆弱性が見つかったということについては過剰に認識していたようです。 鍵の長さは128bitがよく使われているようですね。最近ではコンピュータの計算速度が とても早くなり、並列計算も増えてきたということで160bitや256bitもあるみたいです。 bit長をのばしても問題ないということで、今回は128bit以上で決定しようと思います。

関連するQ&A

  • ある擬似乱数の生成方法について

    ある擬似乱数の生成方法について 『ある周波数とある周波数を組み合わせて作る擬似乱数』という様なことを以前聞いたことがあるのですが、具体的方法をご存知の方がいらっしゃいましたら、教えて下さい! よろしくお願い致します。

  • 暗号学的ハッシュ関数でbit長が適切って作れますか

    SHA256が(224かもですが)最小bit長で、 入力に1bitでも、また2bit以上入力値全体まで、異なれば、 出力のうちほぼ半数のbitが反転する、かつその 反転するbit位置は複数の入力値に対して法則性はなく、 ほぼランダムである。 という暗号学的ハッシュ関数であるのは、正しいですか? また、データの暗号化に使われるパスワードは4096bitを推奨との 事ですが、 SHA4096などその時に合った暗号学的ハッシュ関数を 作るのは難しいのですか? 素人考えでは、今256bitで衝突が見つかってないなら 4096bitならbit長大きいのだから作れそうな気もしますが やはりそういう問題ではないのでしょうか? もし作れるとしたら、データの暗号化に使うパスワードを SHAなんとか・・・の出力そのまま使っては、危険でしょうか? というかデータに限らず認証のパスワードでも SHAなんとかの出力そのままを使うのは何かまずいのでしょうか? もしできたらパスワードを覚えなくてよいのでいいかと思ったのですが。 パスワードは「IDのパスワード」をSHAなんとかに通した値ということで。 IDは「種パスワード+なんとかのサイト」をSHAなんとかに通した値ということで。 種パスワードはしょうがないからネットをパスワードの決め方とかで検索して 出てきた方法を見て理解して自分なりにアレンジして、最後にちゃんと頭に記憶して。 とりあえずここまで、どうでしょうか。

  • ハッシュ関数について質問です。

    プログラミング・数学? 初心者です。 IDやパスワード管理によく出てくる一次方向(ハッシュ)関数ですが、 よくパスワードとSALTを一緒にしてハッシュ関数を通してハッシュ値を取得しますよね。 そしてその結果(データベースなどに記録済み)とログイン時に入力した値とを照らし合わせるわけですが、 昔まだ若いころ、これとは別のタイプのハッシュ関数を使用したことがあります。 それはある(パスワードなどの)値をハッシュ関数で処理すると「いろんなハッシュ値」が生成され、 そのハッシュ値から当然パスワードは予測できないのですが、 しかしその複数のハッシュ値は全て、そのパスワードから生成されたハッシュ値だということは分かる、という関数を使用したことがあります。 その時はperlのcpanモジュール(名前を覚えていません。すいません。)を使ったのですが、この別のタイプのハッシュ関数はどういう仕組みで作られているのでしょうか? SALTが複数あり、そのそれぞれについて照合している?だけでしょうか? それとも私が無知で、そんな関数がそもそも存在するだけでしょうか? わかりません。教えてください。

  • メルセンヌツイスターを使った2次元乱数

    Mersenne Twisterを使って2次元の乱数を下記のように 生成しています。 1. 乱数を取得. x座標の値とする。 2. 1)で用いた乱数生成を利用して乱数を取得. y座標の値とする。 こうした作成したx,y座標のデータを見ますと、一様性が あまりないように見えます。 これは、2次元の乱数の扱いが間違っているのでしょうか? あるいは、周期が非常に長い乱数でも、2次元的に一様性を 保つためには、凖乱数を使うのがいいのでしょうか。

  • 擬似乱数生成について

    お世話になります。 下記、問題について教えてください。   ============ 問題 =============   線形合同法はA,C,Pを秘密の定数(Pは素数),初期値をR1として下記演算によって計算される系列 R1,R2,R3・・・・を擬似乱数として用いる。 R_{i} = A・R_{i-1} + C (mod P) このアルゴリズムと素数Pがわかっているとき、いくつの乱数値がわかれば次の乱数値が計算できるか?その理由も示せ。   ============================= 自分なりに調べてやってみたのですが、いまいちよくよく分かりません。 直感的に、未知数が3個あるので連続した3つの乱数値を各Rとして代入すれば、2元1次方程式を得られ、A,Cが決定できると思ったのですが、どうもうまくいかない・・・ 暗号理論の専門書を読んでみたところ、やはりPが判明いてる場合、連続した3つの値で良いようです。もしPが判明していない場合でも、4つ以上の連続した値から次の乱数値が分かるそうです。 完全に混乱しています。どなたか分かる方、解説していただけませんか。 よろしくお願いします。

  • PHPとJavaでSHA256の結果を同じにしたい

    PHPから JavaServletにアクセスするシステムを作っています。 その際にパラメーターの改ざん対策にハッシュを渡すようにしたいのですが PHPでSHA-256でハッシュ化した値と JavaでSHA-256でハッシュかした値が異なってしまいます。 PHPだとハッシュ化する際の秘密鍵を指定する項目がありますが Javaでは見つかりませんでしたので この項目が違うために結果が違うのだと予想していますが Javaが内部的に使っている秘密鍵はどこか取得できるのでしょうか? やりたいこととしてはPHPとJavaで同じハッシュが取得できるようにしたいのですが 良い案とかやり方あったら教えてください。 ◆php string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] ) ◆Java DigestUtils.sha256Hex(string data) わかる方いましたら教えてください。よろしくお願いいたします。

    • ベストアンサー
    • Java
  • ある乱数生成法により,生成した最初の乱数の値は固定するか確かめて頂きた

    ある乱数生成法により,生成した最初の乱数の値は固定するか確かめて頂きたいです. 0.0から1.0までの一様乱数を発生させる方法です. C言語のコードは以下に載せます. #define IA 16807 #define IM 2147483647 #define AM (1.0/IM) #define IQ 127773 #define IR 2836 #define MASK 123459876 float ran0(long *idum) { long k;   float ans; *idum ^= MASK; k=(*idum)/IQ; *idum=IA*(*idum-k*IQ)-IR*k; if (*idum < 0) *idum += IM; ans=AM*(*idum); *idum ^= MASK; return ans; } この乱数生成法をBVAで,計算の中で繰り返し用いようとしています. idumを任意の整数値に設定・再設定すれば乱数列が初期化されると書いてあったため,idumの値を変えてみましたが,生成された乱数の最初の値は固定されたままでした. そこで,もともとこの乱数生成法がそのようになっているのかを教えて頂きたいです. よろしくお願いします.

  • 疑似乱数評価ツールについて

    現在、大学の研究室でストリーム暗号の研究をしています。 ストリーム暗号の鍵は疑似乱数列が用いられるため、 各アルゴリズムの評価には疑似乱数評価ツールが用いられています。 疑似乱数評価ツールとしてNISTのSP-800 22というツールが 一般的です。 http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html しかしこの評価ツールには計算式のパラメータに不適切なものが いくつかあることがCRYPTRECの調査で指摘され、 プログラム自身にも致命的なバグがあるようです。 ↓情報ソース http://www2.nict.go.jp/y/y213/cryptrec_publicity/rep_ID0211.pdf http://cryptrec.nict.go.jp/rep_ID0037.pdf http://www.chaosware.com/ransure/pdf/ransure2.pdf 実際、私が評価ツールを試したときはプログラムが途中でフリーズしたり デタラメな結果が出たりと散々でした。 マニュアルがとても不親切だしREADMEすらついていないプログラムは全く信用できません。 そのため東芝ソリューションが問題を修正した評価ツールを作成したようですが プログラムはIPA専有となっており、暗号開発者はIPAに評価を委託しなければならないようです。 (しかも法人向きのサービスで、個人だと無理っぽいです) http://www.ipa.go.jp/security/fy17/development/random/documents/rand.pdf 市販されているツールもありますが価格が50万円もします。 +保守料金が年間10万円とありますが そんな大金で何を保守するのか謎です。 http://www.chaosware.com/ransure/ransure.html 私が自分で考案したアルゴリズムを評価するための選択肢は 1.高額な評価ツールを購入する。 2.評価のための計算式は公表されているので自作する。 しかないように思います。 購入してしまえば楽ですがオープンソースではないのでそのツールにもバグが無いことを証明できません。 自作したとしてもそのツールの正統性の証明も困難と思われます。 こういうのは然るべき場所でキチンと議論して オープンソースな開発をしなきゃならないと思うんですが (っていうかNISTがそういう所であるべきなんですが) 論文の〆切も迫ってきていますのでどうしたものかと途方に暮れております。 長くなりましたが何か良い案があれば 教えていただきたいです。

  • 一意(ユニーク)かつ、ソートに対してランダムなIDの発行方法

    随時増加するあるデータに対して、一意なIDを割り当ててゆきます。 通常は、1, 2, 3, … と連番を割り当てて行けば一意なIDになると思います。 その上で、IDでソートした時に発行順に並ぶのではなく、順番がランダムになるようにしたいのです。 (アルゴリズムを知らない人から、発行順を推測されないようにしたい。) そこで考えたのが、"1", "2", "3", …という文字列に対するハッシュ(SHA1やMD5)ですが、sha1("1"), sha1("2"), sha1("3"), …とIDを発行していった場合、IDが重複してしまう可能性を心配しています。(とても低い確率ではあることは分かっていますが、皆無ではありません。) ハッシュ関数を利用する他に、「一意」で「ランダム」で「衝突の可能性がゼロ」である文字列の生成方法はありませんでしょうか?(可能性がゼロというのは物理的に不可能だと思うので、例えばSHA-1であれば、160bitのハッシュが生成されますが、2^160個のIDを発行しても重複しない、ということを考えます。) 一応、規模は1000万ID程度を考えていますが、もっと大きなオーダーでも衝突しないに越したことはありません。

  • 乱数について

    C の入門書を1冊読み終え、簡単なプログラムを作成しようとしているのですが、 早速分からないことが出たので教えて頂ければと思います。 --------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int num; int i = 0; while( i < 4 ){ srand(time(NULL)); num = rand()%100; printf("%d\n", num); i++; } return 0; } --------------------------------------------- 上記を実行したのですが、秒数を乱数の種としているため4回とも同じ値を取得してしまいます。 より高精度に秒数を取得することは可能でしょうか? もしくはこのようなかたちで4回ともに異なる数を得ることが出来る方法がありましたら教えて頂きたいと思います。