SHA算法每次为同一个密钥生成唯一的哈希字符串

时间:2014-11-10 06:56:14

标签: java algorithm encryption hash sha

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

我从他们身上发现了使用散列函数而不是加密来在数据库中存储密码

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

现在我真的无法理解我应该如何使用它,因为每次我传递相同的密码来生成SHA键时,它给我的不同于前一个,而不是我如何将它与我存储的哈希键进行比较数据库?

我正在使用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

1 个答案:

答案 0 :(得分:4)

这是您最直接的问题:

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

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

  

类Object的toString方法返回一个字符串,该字符串由对象为实例的类的名称,符号字符“@”和对象的哈希码的无符号十六进制表示组成。 / p>

(数组也不会覆盖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而不是
  • 您应该至少使用随机盐来避免在数据库中具有相同值的相同密码。 (否则,攻击者可以利用这些信息。)

我远非安全方面的专家,所以我不会就正确的做事方式向你提供更多建议 - 但我实际上建议你找一个安全专家写的备受尊重的图书馆,而不是试图自己实现这个。安全性很难做得很好。