_SHA1
_アルゴリズムを使用してdbに保存されているパスワードを復号化(実際の文字列を保持)することは可能ですか?.
例:パスワードが_"password"
_で、_"sha1$4fb4c$2bc693f8a86e2d87f757c382a32e3d50fc945b24"
_としてdbに保存されている場合、_"sha1$4fb4c$2bc693f8a86e2d87f757c382a32e3d50fc945b24"
_から同じ"password"(string)
を保持する機会があります
SHA1
は暗号化ハッシュ関数であるため、設計の意図は、ユーザーがしようとしていることを回避することでした。
ただし、SHA1
ハッシュの破壊は技術的には可能です。ハッシュ化されたものを推測しようとするだけでこれを行うことができます。このブルートフォースアプローチは、もちろん効率的ではありませんが、それがほとんど唯一の方法です。
あなたの質問に答えるために:はい、それは可能ですが、あなたにはかなりの計算能力が必要です。一部の研究者は、 費用が$ 70k-$ 120k と見積もっています。
今日わかる限り、ハッシュされた入力を推測する以外に方法はありません。これは、mod
などの操作が入力から情報を削除するためです。 mod 5
を計算し、0
を取得するとします。入力は何でしたか? 0
、5
、または500
でしたか?この場合、本当に「戻る」ことはできません。
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
の間のASCII文字のみを使用するためです。
最後に報告された衝突を取り、チェックしましょう
System.out.println("VvV".hashCode());
System.out.println("WWV".hashCode());
私の出力は
86390
86390
結論:
SHA-1値があり、入力値を取り戻したい場合は、ブルートフォース攻撃を試すことができます。これは、可能なすべての入力値を生成し、それらをハッシュし、所有しているSHA-1と比較する必要があることを意味します。しかし、それは多くの時間と計算能力を消費します。一部の人は、一部の入力セットに対して、いわゆるRainbowテーブルを作成しました。しかし、これらはいくつかの小さな入力セットに対してのみ存在します。
また、多くの入力値が単一のターゲットハッシュ値にマッピングされることを忘れないでください。したがって、すべてのマッピングを知っていたとしても(入力セットには制限がないため不可能です)、どの入力値であったかを言うことはできません。
SHA-1は複数のバイトシーケンスを1つにマッピングするため、ハッシュを「復号化」することはできませんが、理論的には、同じハッシュを持つ文字列の衝突を見つけることができます。
現在、単一のハッシュを破ると約 270万ドル のコンピューター時間に相当するコストがかかるようです。