要保存文件,我定义了以下方法
public int encrypt(String fileName, String password) {
return (fileName.concat(password)).hashCode();
}
这将返回存储在文件中的哈希值。每当用户想要访问该文件时,他都会输入密码,如果生成了相同的哈希,他就可以访问该文件。
我认为这不是很安全,但它有多安全? String#hashCode用两个不同的输入生成相同哈希的机会有多高?
编辑:
根据你的回答,我改变了代码:
public String encrypt(String password) {
String hash = "";
try {
MessageDigest md5 = MessageDigest.getInstance("SHA-512");
byte [] digest = md5.digest(password.getBytes("UTF-8"));
hash = Arrays.toString(digest);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return hash;
}
所以它现在应该更好??
答案 0 :(得分:17)
这是一个坏主意 - 您应该使用正常的加密哈希值,例如SHA-1,就像NullUserException所说的那样。
但是, 可以移植 - String.hashCode()
的文档明确说明算法。任何正确实现文档的JRE都应该提供相同的哈希码。但是,由于hashCode()
算法的工作方式,很容易找到一个生成任何特定哈希码的字符串 - 即使是以特定前缀开头的代码 - 所以知道哈希的攻击者可能会攻击你的应用程序非常简单地。加密哈希旨在使密钥难以设计以匹配特定哈希值。
答案 1 :(得分:5)
依靠非加密函数来提供安全相关的目的通常是一个坏主意。由于您无法确定使用哪个实现(并将在未来使用)来计算字符串的哈希码,因此您应该更喜欢加密安全哈希码算法。我建议使用SHA-1或SHA-256。 http://www.bouncycastle.org/具有许多哈希算法的实现。
答案 2 :(得分:5)
String.hashCode
不适合散列密码。您需要加密哈希。
String.hashCode
旨在快速计算。它的主要用途是用于哈希表中的密钥。对于这种用途,偶尔的碰撞不是问题。加密哈希的计算速度较慢,但根据定义,没有人知道如何为良好的加密生成冲突。
更重要的是,考虑到password.hashCode()
的价值,可以找到password
(具有高可信度,但由于许多密码具有相同的哈希值,因此不确定)。这不是你想要发生的事情。另一方面,加密哈希的设计使得无法找到知道哈希的密码(从数学上讲,没有人知道如何在哈希值的生命周期中找到密码)。
Java标准库中提供了加密哈希,通过java.security.MessageDigest。
ADDED :还有一个复杂问题:直接哈希密码是个坏主意。原因是攻击者可以尝试所有可能的密码(例如字典单词,人名等)。此问题的标准解决方案是将密码与名为{{3}的随机字符串连接起来。在计算哈希之前:你做的就像sha.digest((salt+password).getBytes())
一样。盐使得攻击者预先计算可能密码的所有哈希值是不切实际的。
通常在用户选择他/她的密码时随机生成盐,并将其存储在用户数据库中的密码哈希旁边,但是根据您显示的方案,没有这样的东西。根据您的设计,将文件名用作盐:fileName.concat(encrypt(fileName + password))
。
答案 3 :(得分:2)
老实说,我不知道Java的hashCode()
是如何抗冲突的。如果我猜,我会说不是很好。我之前测试过它,在几十万输入之后发现了几次碰撞。
由于您在此处理密码,因此您应该使用像SHA1这样的加密哈希。
答案 4 :(得分:2)
它并不像您想象的那样难以散列数据,并且最好使用真正的散列算法。如果你有一个包含密码的字节数组,你可以这样做。如果从字符串中获取字节数组,请确保在调用getBytes()时指定编码(即UTF-8);
以下是使用MD5的简单示例。
try {
MessageDigest md5 = MessageDigest.getInstance( "MD5" );
byte [] digest = md5.digest( data );
return digest;
} catch( java.security.NoSuchAlgorithmException ex ) {
// Insert error handling here.
}
答案 5 :(得分:1)
我担心这段代码是不可移植的。无法保证一个JVM将生成与另一个JVM相同的哈希值。这似乎非常危险。
答案 6 :(得分:1)
这是String.hashCode()的实现:
s [0] * 31 ^(n-1)+ s [1] * 31 ^(n-2)+ ... + s [n-1]
公开提供here ...
这实际上与VM无关,并且过去并不依赖于Java版本。实施保持不变。
碰撞安全是可以的恕我直言,但出于显而易见的原因将其用于加密目的是一个坏主意。
答案 7 :(得分:0)
#1问题是哈希只有32位。这太短了。一个有BASIC的孩子可以在一秒钟内打破它。
md5是128位长,现在它被认为是弱的。