SHA1 - это односторонний хэш. Таким образом, вы не можете вернуть его обратно.
Вот почему приложения используют его для хранения хеш-кода пароля, а не самого пароля.
Как и любая хеш-функция, SHA-1 сопоставляет большой входной набор (ключи) с меньшим целевым набором (хеш-значениями). Таким образом могут произойти столкновения. Это означает, что два значения входного набора соответствуют одному и тому же хэш-значению.
Очевидно, что вероятность столкновения увеличивается, когда целевой набор становится меньше. Но наоборот, это также означает, что вероятность столкновения уменьшается, когда целевой набор становится больше, а целевой набор SHA-1 составляет 160 бит.
Джефф Прешинг написал очень хороший блог о вероятностях хеш-коллизии это может помочь вам решить, какой алгоритм хеширования использовать. Спасибо, Джефф.
В своем блоге он показывает таблицу, которая сообщает нам вероятность коллизий для заданного набора входных данных.
![Таблица вероятностей хеш-коллизий](https://i.stack.imgur.com/1ldEA.png)
Как видите, вероятность 32-битного хеширования равна 1 из 2, если у вас есть 77163 входных значения.
Простая программа на 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. Это не точно 1 из 10, но это всего лишь вероятность, а пример программы не идеален. , потому что он использует только символы ascii между A
и z
.
Возьмем последнее зарегистрированное столкновение и проверим
System.out.println("VvV".hashCode());
System.out.println("WWV".hashCode());
Мой результат
86390
86390
Вывод:
Если у вас есть значение SHA-1 и вы хотите вернуть входное значение, вы можете попробовать атаку методом грубой силы. Это означает, что вам нужно сгенерировать все возможные входные значения, хешировать их и сравнить с имеющимся у вас SHA-1. Но это потребует много времени и вычислительной мощности. Некоторые люди создали так называемые радужные таблицы для некоторых наборов входных данных. Но они существуют только для некоторых небольших входных наборов.
И помните, что многие входные значения соответствуют одному целевому хеш-значению. Таким образом, даже если вы знаете все сопоставления (что невозможно, потому что набор входных данных неограничен), вы все равно не можете сказать, какое это было входное значение.
person
René Link
schedule
19.09.2013