我的Salting和SHA-512散列密码的实现是否正确/安全?

时间:2014-02-17 18:29:55

标签: java security cryptography salt sha512

我的Salting和SHA-512哈希密码的实现是否正确/安全?

我知道我应该在盐渍密码上多次迭代算法。除此之外,我应该实施什么才能使其安全或足够?

        public static String[] SHA512(String password)
{
    //Generates the salt
    SecureRandom saltRandomizer = new SecureRandom();
    byte[] salt = new byte[64]; //The same size as the output of SHA-512 (512 bits = 64 bytes)
    saltRandomizer.nextBytes(salt);
    String encodedSalt = Base64.encodeToString(salt, Base64.DEFAULT);


    //Prepends the salt to the password
    String saltedPassword = encodedSalt + password;

    //Hashed the salted password using SHA-512
    MessageDigest digester;
    byte[] digest = null;
    try {
        digester = MessageDigest.getInstance("SHA-512");
        digester.reset();
        digester.update(saltedPassword.getBytes());
        digest = digester.digest();
    } catch (NoSuchAlgorithmException e) {
        System.out.println("No such algorithm");
        e.printStackTrace();
    }

    String[] passwordPlusSalt = new String[2];
    passwordPlusSalt[0] = Base64.encodeToString(digest, Base64.DEFAULT);
    passwordPlusSalt[1] = encodedSalt;
    return passwordPlusSalt;
}

提前致谢

2 个答案:

答案 0 :(得分:6)

没有。这不安全。看看这一行:

SecureRandom saltRandomizer = new SecureRandom();

我注意到您没有指定PRNG或提供商。我不是专家,但我理解SUN CSP的默认设置是在Solaris和Linux上使用sun.security.provider.NativePRNG,它只提供/ dev / urandom的输出,它可能(或可能不)适合您的需要(例如,建议不要生成加密密钥)。

因此,建议始终指定PRNG和提供者,如下所示:

SecureRandom.getInstance("SHA1PRNG", "SUN");

此外,建议:

  • 定期丢弃现有的java.security.SecureRandom实例并创建一个新实例。这将生成一个带有新种子的新实例。
  • 通过调用java.security.SecureRandom.setSeed(java.security.SecureRandom.generateSeed(int)),定期向PRNG种子添加新的随机材料。

我要说的是,安全性是一个很容易出错的复杂话题。不要试图自制一个解决方案。使用现有库。引用Thomas Pornin的优秀答案:

  

复杂性很糟糕。自制很糟糕。新的很糟糕。

来源:

答案 1 :(得分:2)

我认为采取措施使用盐哈希密码是保护应用程序和访问更高安全级别的一个很好的步骤。但是,您的实施存在问题:

  • 不使用种子进行随机字节生成
  • 不跟踪生成的随机字节以将其用于密码验证
  • 使用字符串连接不会增加算法的复杂性,但看起来像默默无闻的安全性,已被证明在安全关键环境中效率低下。

相反,请使用专为您的需求而设计的标准HMAC算法。可以使用java 7支持的算法列表here。 PBKDF2WithHmacSHA1是个不错的选择。 它可以简单地像这样使用:

PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] secretPassword = skf.generateSecret(spec).getEncoded();

可以找到完整的工作代码here。如果您的密码数据库落入坏人手中,它应该限制暴力/字典攻击的影响。

请注意,盐是一种致命的环。根据您的安全要求,您可以将其存储在单独的文件系统中,在服务器启动时键入或加载它。甚至可以有专门的(通常是昂贵的)硬件安全模块,可以保证安全。