web-dev-qa-db-ja.com

Cでハッシュ関数を書く方法は?

ハッシュテーブルは、データを格納/取得するための最速/最良の方法であると言われています。

ハッシュテーブルについての私の理解、ハッシュは次のとおりです(間違っている場合は訂正してください。それ以外にあれば追加してください)。

  • あ ハッシュ表 値を格納する配列(単一または多次元)にすぎません。
  • ハッシュ データを挿入/取得する配列内のインデックス/場所を見つけるプロセスです。データ項目を取得し、それをキーとしてハッシュ関数に渡すと、データを挿入/取得するためのインデックス/場所が取得されます。

質問があります:

ハッシュ関数は、MD5、HMAC、SHA-1などの認証用のセキュリティアプリケーションで使用される暗号化ハッシュ関数とは異なるデータの格納/取得に使用されますか?

それらはどのような点で異なりますか?

  • Cでハッシュ関数を書く方法は?
  • 基準やガイドラインはありますか?
  • ハッシュ関数の出力、つまりインデックスが範囲外にならないようにするにはどうすればよいですか?

あなたがこれらをよりよく理解するためにいくつかの良いリンクに言及できたら素晴らしいでしょう。

27
aks

暗号化ハッシュは、誰かが意図的に衝突を作成することを困難にすることを強調しています。ハッシュテーブルの場合、通常、結果の妥当な広がりを生成することに重点が置かれますquickly。そのため、通常2つはかなり異なります(特に、暗号化ハッシュは通常lot遅くなります)。

典型的なハッシュ関数の場合、結果はタイプによってのみ制限されます。 size_tを返す場合、any可能なsize_tを返すことはまったく問題ありません。その出力範囲をテーブルのサイズに縮小するのはあなた次第です(たとえば、多くの場合素数である必要があるテーブルのサイズで割った余りを使用します)。

例として、かなり一般的な通常のハッシュ関数は次のようになります。

// warning: untested code.
size_t hash(char const *input) { 

    const int ret_size = 32;
    size_t ret = 0x555555;
    const int per_char = 7;

    while (*input) { 
        ret ^= *input++;
        ret = ((ret << per_char) | (ret >> (ret_size - per_char));
   }
   return ret;
}

ここでの基本的な考え方は、入力文字列のすべてのビットに結果に影響を与え、(可能な限り迅速に)結果のすべてのビットに入力の少なくとも一部に影響を与えることです。これを優れたハッシュ関数として特に推奨しているわけではないことに注意してください。達成しようとしていることの基本の一部を示すことだけを目的としています。

11
Jerry Coffin

Bob Jenkinsは、少し古くなっている場合は ハッシュ関数 を使用して、彼の財について詳細な説明を書きました。この記事には、新しい、より優れたハッシュ関数へのリンクがありますが、この記事では、優れたハッシュ関数を作成することについての懸念を取り上げています。

また、ほとんどのハッシュテーブルの実装では、リンクリストの配列を使用して衝突を解決しています。配列のみを使用する場合、ハッシュ関数は衝突をチェックし、新しいハッシュインデックスを作成する必要があります。

あなたが言及する暗号ハッシュ関数は、ハッシュテーブルのハッシュ関数として使用できますが、ハッシュテーブル用に設計されたハッシュ関数よりもはるかに低速です。速度はブルートフォース攻撃を容易にします。

4
RossFabricant

設計目標は異なります。

暗号化ハッシュ関数 を使用すると、たとえば、ハッシュとハッシュ関数を使用して、元のデータまたは同じハッシュを生成する他のデータを決定できないようにすることができます。

ハッシュテーブルやその他のデータ構造で使用されるハッシュ関数は、このようなセキュリティプロパティを必要としません。ハッシュ関数が高速であり、入力セットを可能なハッシュのセットに均等に分散する場合は十分です(不要なクラスタリング/衝突を回避するため)。

0
Anssi