java - SHA 算法每次为相同的 key 生成唯一的哈希字符串

标签 java algorithm encryption hash sha

我知道有很多关于散列和加密算法的文章。

我从他们那里了解到使用散列函数而不是加密将密码存储在数据库中

所以我决定使用 SHA-256 算法生成散列 key ,并将该散列 key 存储到我的服务器数据库中,而不是普通密码。

现在我真的无法理解我应该如何使用它,因为每次我传递相同的密码来生成 SHA key 时,它给我的结果与以前的不同,我怎么能将它与我存储的哈希 key 进行比较数据库?

我正在使用 java,所以我的 java 代码是

public class Test {
public static void main(String...arg) throws IOException{
    System.out.println("First time");
    String string64 = getEncryptedPassword("FenilShah");
    System.out.println(string64);
    System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(string64)));

    System.out.println("\nSecond time");
    string64 = getEncryptedPassword("FenilShah");
    System.out.println(string64);
    System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(string64)));

    System.out.println("\nThird time");
    string64 = getEncryptedPassword("FenilShah");
    System.out.println(string64);
    System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(string64)));

}

 public static String getEncryptedPassword(String clearTextPassword)   {  


        try {
          MessageDigest md = MessageDigest.getInstance("SHA-256");
          md.update(clearTextPassword.getBytes());
          byte pass[] = md.digest();
          System.out.println(pass.toString());
          return Base64.encodeBase64String(StringUtils.getBytesUtf8(pass.toString()));
        } catch (NoSuchAlgorithmException e) {
          //_log.error("Failed to encrypt password.", e);
        }
        return "";
      }
 }

所以输出是这样的

First time
[B@5bf825cc
W0JANWJmODI1Y2M=
[B@5bf825cc

Second time
[B@1abfb235
W0JAMWFiZmIyMzU=
[B@1abfb235

Third time
[B@1f4cc34b
W0JAMWY0Y2MzNGI=
[B@1f4cc34b

最佳答案

这是您最紧迫的问题:

byte pass[] = md.digest();
System.out.println(pass.toString());

您不会返回字符串的哈希值。您正在返回对 byte[] 调用 toString() 的结果。 Java 中的数组不会覆盖 toString(),因此您将获得默认实现,它与对象的标识有关,与数据无关在字节数组中:

The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object.

(数组也不会覆盖 hashCode(),所以它也是从 Object 中的默认实现中获得的...)

基本上,您需要一种不同的方法将 byte[] 转换为 String... 当然,或者将字节数组直接存储在数据库中。如果您确实想要转换为字符串,我建议您使用 hex 或 base64。对于 base64,我建议使用 iharder.net public domain library ...或者如果您使用的是 Java 8,则可以使用 java.util.Base64 . (令人惊讶的是,在 XML 等以外的上下文中将 base64 类放入标准库中花费了这么长时间,但我们开始了。)

return Base64.getEncoder().encodeToString(md.digest());

您的代码还有一个问题:

md.update(clearTextPassword.getBytes());

这使用平台默认编码将密码转换为字节数组。这不是一个好主意——这意味着您最终可能会根据代码运行的系统获得不同的哈希值。最好明确指定编码:

md.update(clearTextPassword.getBytes(StandardCharsets.UTF_8));

此外,如果缺少 SHA-256,则捕获异常、记录并继续使用空白字符串几乎肯定是错误的方法。你真的想用空字符串填充你的数据库,允许任何人使用任何密码登录吗?如果你的系统处于那种状态,你能做的最好的事情几乎肯定是让任何使用密码做任何事情的请求都失败。您可能希望将 NoSuchAlgorithmException 转换为某种类型的 RuntimeException 并重新抛出。

最后,无论如何存储一个简单的 SHA-256 散列可能不是一个好主意。

  • 你可能想要一个 HMAC相反
  • 您应该至少使用随机盐以避免相同的密码在数据库中具有相同的值。 (否则,攻击者可以利用该信息为他们谋取利益。)

我远不是安全专家,所以我不会就正确的做事方式提供更多建议 - 但实际上我会建议尝试找到一个由安全专家编写的备受推崇的库,而不是尝试自己实现。安全很难做好。

关于java - SHA 算法每次为相同的 key 生成唯一的哈希字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26838341/

相关文章:

java - 如何通过ArrayList递增并改变其状态?

php - 固定比例选择

algorithm - 颠倒单词的顺序——时间复杂度?

c - 在c中实现异或加密时没有输出到磁盘

php - RC4 加密 - CommonCrypto (Objective-C) 与 PHP

c++ - 错误在哪里?显示字符串 C++ Vigenere 密码

Java-基于 Https 的 SOAP Web 服务

java - 安卓广播接收器 : Unable to instantiate receiver - no empty constructor

java - 一类 svm 是否提供概率估计?

Python - 找到最近的时间戳