是否可以使用SHA1
算法解密(保留实际字符串)保存在数据库中的密码。
示例:如果密码是"password"
并且它存储在数据库中"sha1$4fb4c$2bc693f8a86e2d87f757c382a32e3d50fc945b24"
,是否有机会"password"(string)
从"sha1$4fb4c$2bc693f8a86e2d87f757c382a32e3d50fc945b24"
是否可以使用SHA1
算法解密(保留实际字符串)保存在数据库中的密码。
示例:如果密码是"password"
并且它存储在数据库中"sha1$4fb4c$2bc693f8a86e2d87f757c382a32e3d50fc945b24"
,是否有机会"password"(string)
从"sha1$4fb4c$2bc693f8a86e2d87f757c382a32e3d50fc945b24"
SHA1
是一个密码散列函数,因此设计的目的是避免您尝试做的事情。
然而,打破SHA1
哈希在技术上是可能的。您可以通过尝试猜测散列的内容来做到这一点。这种蛮力方法当然效率不高,但这几乎是唯一的方法。
所以回答你的问题:是的,这是可能的,但你需要强大的计算能力。一些研究人员估计它的成本为 7 万至 12 万美元。
据我们今天所知,除了猜测散列输入之外别无他法。这是因为诸如mod
消除输入中的信息之类的操作。假设您计算mod 5
并得到0
。输入是什么?是0
,5
还是500
?你看,在这种情况下你不能真正“回去”。
SHA1 是一种单向哈希。所以你不能真正恢复它。
这就是为什么应用程序使用它来存储密码的哈希而不是密码本身。
与每个散列函数一样,SHA-1 将大型输入集(键)映射到较小的目标集(散列值)。因此可能会发生碰撞。这意味着输入集的两个值映射到相同的哈希值。
显然,当目标集越来越小时,碰撞概率会增加。但反之亦然,这也意味着当目标集越来越大并且 SHA-1 的目标集为 160 位时,冲突概率会降低。
Jeff Preshing写了一篇关于Hash Collision Probabilities的非常好的博客,可以帮助您决定使用哪种哈希算法。谢谢杰夫。
在他的博客中,他展示了一个表格,告诉我们给定输入集的冲突概率。
如您所见,如果您有 77163 个输入值,则 32 位散列的概率为 2 分之一。
一个简单的 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。这不是十分之一,但这只是一个概率,示例程序并不完美, 因为它只使用 和 之间的 asciiA
字符z
。
让我们采取最后报告的碰撞并检查
System.out.println("VvV".hashCode());
System.out.println("WWV".hashCode());
我的输出是
86390
86390
结论:
如果你有一个 SHA-1 值并且你想取回输入值,你可以尝试暴力攻击。这意味着您必须生成所有可能的输入值,对它们进行散列并将它们与您拥有的 SHA-1 进行比较。但这会消耗大量的时间和计算能力。有些人为某些输入集创建了所谓的彩虹表。但这些只存在于一些小的输入集。
请记住,许多输入值映射到单个目标哈希值。所以即使你知道所有的映射(这是不可能的,因为输入集是无界的)你仍然不能说它是哪个输入值。
由于 SHA-1 将多个字节序列映射为一个,因此您无法“解密”散列,但理论上您可以找到冲突:具有相同散列的字符串。
目前看来,破解单个哈希值将花费大约270 万美元的计算机时间,因此您的努力可能最好花在其他地方。