Java 我可以使用Object#hashCode来存储密码的散列吗?

Java 我可以使用Object#hashCode来存储密码的散列吗?,java,security,hash,Java,Security,Hash,为了保存文件,我定义了以下方法 public int encrypt(String fileName, String password) { return (fileName.concat(password)).hashCode(); } 这将返回存储在文件中的哈希值。每当用户想要访问该文件时,他都会输入密码,如果生成相同的哈希,他就可以访问该文件 我想这不是很安全,但它有多安全?String#hashCode使用两个不同的输入生成相同哈希的可能性有多大 编辑: 根据你的回答,我更改了密

为了保存文件,我定义了以下方法

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;
    }

所以现在应该更好了???

老实说,我不知道Java的
hashCode()
抗冲突能力有多强。如果让我猜的话,我会说不太可能。我之前测试过它,在几十万次输入后发现了几次碰撞


因为您在这里处理密码,所以应该真正使用像SHA1这样的加密散列。

依靠非加密函数来实现安全相关目的通常是个坏主意。由于您永远无法确定使用哪个实现(以及将来将使用哪个实现)来计算字符串的哈希代码,因此您应该更喜欢加密安全哈希代码算法。我建议使用SHA-1或SHA-256。有许多散列算法的实现。

我担心这段代码不可移植。不能保证一个JVM将产生与另一个JVM相同的哈希值。这似乎非常危险。

字符串。hashCode不适合对密码进行哈希运算。您需要一个加密哈希


String.hashCode
设计的计算速度非常快。它主要用于哈希表中的键。在这种情况下,偶尔发生碰撞不是问题。加密散列的计算速度较慢,但根据定义,没有人知道如何为一个好的加密散列生成冲突

更重要的是,给定
password.hashCode()
的值,可以找到
password
(具有很高的可信度,但由于许多密码具有相同的哈希值,因此不确定)。这不是你想发生的事。另一方面,加密散列的设计使得不可能在知道散列的情况下找到密码(从数学上讲,没有人知道如何在其生命周期中从散列中找到密码)

加密散列可以在Java标准库中通过获得

添加了:还有一个复杂问题:直接散列密码是个坏主意。原因是攻击者可以尝试所有可能的密码(例如字典单词、人名等)。此问题的标准解决方案是在计算哈希之前将密码与名为a的随机字符串连接起来:您可以执行类似于
sha.digest((salt+password).getBytes())
的操作。salt使得攻击者预先计算所有可能密码的哈希值是不合法的


通常,salt是在用户选择其密码时随机生成的,它存储在用户数据库中密码散列的旁边,但是从您对方案的显示来看,没有这样的事情。根据您的设计,使用文件名作为salt是合理的:
filename.concat(encrypt(filename+password))

这是一个坏主意-您应该使用普通的加密散列,如NullUserException所说的SHA-1

但是,它是可移植的,
String.hashCode()
的文档明确地说明了算法。任何正确实现文档的JRE都应该给出相同的哈希代码。但是,由于
hashCode()
算法的工作方式,很容易找到一个字符串,该字符串将生成任何特定的哈希代码(即使是以特定前缀开头的哈希代码),因此知道该哈希的攻击者很容易攻击您的应用程序。加密散列的设计目的是使设计密钥以匹配特定散列变得困难。

以下是String.hashCode()的实现:

s[0]*31^(n-1)+s[1]*31^(n-2)+…+s[n-1]

公开获取

这实际上是独立于VM的,并且在过去并不依赖于Java版本。执行情况保持不变


碰撞安全是可以的,但是出于明显的原因将其用于加密目的是个坏主意。

散列数据并不像您想象的那么难,最好使用真正的散列算法。如果您有一个包含密码的字节数组,您可以这样做。如果从字符串获取字节数组,请确保在调用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.
    }
#1的问题是哈希值只有32位。那太短了。一个有基本技能的孩子可以在一秒钟内打破它


md5是128位长,现在被认为是弱的

你肯定找不到密码(毕竟,会有许多字符串都散列为相同的值),但你可以找到一个给出相同散列的字符串。@Jon:如果你假设密码由可打印字符组成,并且长度范围很窄,那么你很有可能找到它。这才是真正的奖赏,因为用户重复使用他们的密码。是的,这是一个合理的机会。你的编辑会更好:)散列算法是可以跨JVM移植的。啊,是的,忘了有一个为字符串定义的特殊版本。好主意。前几天晚上我在搞排列,在9中发现了hashcode()冲突!谢谢。有没有可能我不必返回字节数组?嗯,你可以返回你想要的任何东西。摘要的返回值是字节数组。如果希望返回字符串,可以对其进行十六进制或base64编码。
返回新字符串(摘要,字符集.UTF_8)(需要番石榴作为字符集常量)很好的例子,但我不推荐MD5作为密码。MD5并不是因为它的长度而被认为很弱,而是因为它们找到了一种方法