SHA1 は一方向ハッシュです。したがって、実際には元に戻すことはできません。
そのため、アプリケーションはこれを使用して、パスワード自体ではなく、パスワードのハッシュを保存します。
すべてのハッシュ関数と同様に、SHA-1 は大きな入力セット (キー) を小さなターゲット セット (ハッシュ値) にマップします。したがって、衝突が発生する可能性があります。これは、入力セットの 2 つの値が同じハッシュ値にマップされることを意味します。
明らかに、ターゲット セットが小さくなると、衝突の確率が高くなります。しかしその逆もまた、ターゲット セットが大きくなり、SHA-1 のターゲット セットが 160 ビットである場合に衝突確率が低下することを意味します。
Jeff Preshingは、使用するハッシュ アルゴリズムを決定するのに役立つHash Collision Probabilitiesに関する非常に優れたブログを書きました。ありがとうジェフ。
彼のブログでは、特定の入力セットの衝突の確率を示す表を示しています。
ご覧のとおり、77163 個の入力値がある場合、32 ビット ハッシュの確率は 2 分の 1 です。
シンプルな Java プログラムは、彼のテーブルが示す内容を示します。
public class Main {
public static void main(String[] args) {
char[] inputValue = new char[10];
Map<Integer, String> hashValues = new HashMap<Integer, String>();
int collisionCount = 0;
for (int i = 0; i < 77163; i++) {
String asString = nextValue(inputValue);
int hashCode = asString.hashCode();
String collisionString = hashValues.put(hashCode, asString);
if (collisionString != null) {
collisionCount++;
System.out.println("Collision: " + asString + " <-> " + collisionString);
}
}
System.out.println("Collision count: " + collisionCount);
}
private static String nextValue(char[] inputValue) {
nextValue(inputValue, 0);
int endIndex = 0;
for (int i = 0; i < inputValue.length; i++) {
if (inputValue[i] == 0) {
endIndex = i;
break;
}
}
return new String(inputValue, 0, endIndex);
}
private static void nextValue(char[] inputValue, int index) {
boolean increaseNextIndex = inputValue[index] == 'z';
if (inputValue[index] == 0 || increaseNextIndex) {
inputValue[index] = 'A';
} else {
inputValue[index] += 1;
}
if (increaseNextIndex) {
nextValue(inputValue, index + 1);
}
}
}
私の出力は次で終わります:
Collision: RvV <-> SWV
Collision: SvV <-> TWV
Collision: TvV <-> UWV
Collision: UvV <-> VWV
Collision: VvV <-> WWV
Collision: WvV <-> XWV
Collision count: 35135
35135 回の衝突が発生しましたが、これは 77163 回のほぼ半分です。30084 個の入力値でプログラムを実行した場合、衝突回数は 13606 回です。これは正確には 10 分の 1 ではありませんが、確率にすぎず、サンプル プログラムは完全ではありません。A
との間のアスキー文字のみを使用するためz
です。
最後に報告された衝突を確認してみましょう
System.out.println("VvV".hashCode());
System.out.println("WWV".hashCode());
私の出力は
86390
86390
結論:
SHA-1 値があり、入力値を取得したい場合は、ブルート フォース攻撃を試すことができます。これは、可能なすべての入力値を生成し、それらをハッシュして、所有している SHA-1 と比較する必要があることを意味します。しかし、それは多くの時間と計算能力を消費します。一部の人々は、一部の入力セットに対していわゆるレインボー テーブルを作成しました。しかし、これらはいくつかの小さな入力セットに対してのみ存在します。
また、多くの入力値が 1 つのターゲット ハッシュ値にマップされることに注意してください。したがって、たとえすべてのマッピングを知っていたとしても (入力セットが無限であるため、これは不可能です)、それがどの入力値であったかを言うことはできません。