SHA算法每次为同一密钥生成唯一的哈希字符串 [英] SHA algorithm generates each time unique hash string for a same key

查看:140
本文介绍了SHA算法每次为同一密钥生成唯一的哈希字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know there are lots lots of articles available about hashing and encryption algorithm.

我从他们那里弄清楚了,他们使用散列功能而不是加密将密码存储在数据库中.

I have figure it out from them that use hashing function instead of encryption to store password in the database.

因此,我决定使用SHA-256算法生成哈希密钥,并将该哈希密钥(而不是普通密码)存储到服务器数据库中.

So I decided to use SHA-256 algorithm to generate hash key and I am storing that hash key into my server database instead of plain password.

现在,我真的不明白我应该如何使用它,因为每次我传递相同的密码来生成SHA密钥时,它都会给我与以前的密码不同的地方,而不是如何将其与存储在我的哈希密钥中的密码进行比较数据库?

Now I am really not able to understand how I should use it, because each time I am passing the same password to generate SHA key it gives me different than previous one, than how could I compare it with stored hash key in my database?

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

I am using java so my java code is

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(),因此您将获得默认实现,该实现与对象的标识有关,而与数据无关在字节数组中:

You're not returning the hash of the string. You're returning the result of calling toString() on a byte[]. Arrays in Java don't override toString(), so you get the default implementation, which has everything to do with the identity of the object and nothing to do with the data in the byte array:

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

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 中的默认实现中获得的.)

(Arrays don't override hashCode() either, so that's obtained from the default implementation in Object too...)

基本上,您当然需要一种将 byte [] 转换为 String ...的方法,或者直接将字节数组存储在数据库中.如果您想将它们转换为字符串,建议您使用十六进制或base64.对于base64,我建议使用 iharder.net公共域库 ...或者如果您使用的是Java 8,,则可以使用 java.util.Base64 .(令人惊讶的是,在非XML等上下文中将base64类放入标准库中花费了很长时间,但是我们去了.)

Basically, you need a different way of converting a byte[] to a String... or store the byte array directly in the database, of course. If you do want to convert to a string, I suggest you use either hex or base64. For base64, I'd suggest the iharder.net public domain library... or if you're using Java 8, you can use java.util.Base64. (It's astonishing that it took so long to get a base64 class into the standard libraries in a context other than XML etc, but there we go.)

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

您的代码还有另一个问题:

Your code has an additional problem though:

md.update(clearTextPassword.getBytes());

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

This uses the platform default encoding to convert the password into a byte array. That's not a good idea - it means you could end up getting different hashes based on what system your code is running on. It's better to specify the encoding explicitly:

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

此外,如果缺少SHA-256,则捕获异常,记录日志并继续使用空白字符串几乎肯定是错误的方法.您是否真的要用空字符串填充数据库,从而允许任何人使用任何密码登录?如果您的系统处于该状态,则几乎可以肯定的是,您可以做的最好的事情是使任何使用密码执行任何操作的请求都失败.您可能想将 NoSuchAlgorithmException 转换为某种 RuntimeException 并重新抛出.

Additionally, catching an exception if SHA-256 is missing, logging and continuing with a blank string is almost certainly the wrong approach. Do you really want to populate your database with empty strings, allowing anyone to log in with any password? If your system is in that state, the best thing you can do is almost certainly to fail any request to do anything with passwords. You probably want to convert the NoSuchAlgorithmException into some sort of RuntimeException and rethrow.

最后,存储简单的SHA-256哈希可能不是一个好主意.

Finally, storing a simple SHA-256 hash probably isn't a good idea anyway.

  • 您可能希望使用 HMAC
  • 您应该至少使用随机盐,以避免相同的密码在数据库中具有相同的值.(否则,攻击者可以利用这些信息来发挥自己的优势.)
  • You probably want an HMAC instead
  • You should at least use a random salt to avoid the same passwords having the same values in the database. (Otherwise, an attacker can use that information to their advantage.)

我距离安全专家还很遥远,所以我不会就正确的处理方法向您提供更多建议-但实际上,我建议您尝试寻找一个由安全专家编写的受人尊敬的库,而不是尝试自己实现.安全很难做对.

I'm far from an expert on security, so I won't advise you much further on the right way to do things - but I would actually suggest trying to find a well-respected library written by security experts rather than trying to implement this yourself. Security it very hard to do right.

这篇关于SHA算法每次为同一密钥生成唯一的哈希字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆