如何在Java中为Salted-Hash生成SALT? [英] How do I generate a SALT in Java for Salted-Hash?

查看:451
本文介绍了如何在Java中为Salted-Hash生成SALT?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找,最接近的答案是:如何生成一个随机的字母数字字符串?



我想按照这个 CrackStation教程


要存储密码


  1. 使用CSPRNG生成长时间的随机盐。


  2. 将盐加入密码,并使用标准的加密散列函数(如SHA256)进行散列。


  3. 将盐和用户数据库记录中的哈希。


验证密码


  1. 从数据库中检索用户的盐和哈希。


  2. 盐给给定的密码和使用相同的哈希函数对其进行散列。


  3. 将给定密码的哈希与数据库中的哈希进行比较。如果他们匹配,密码是正确的。否则,密码不正确。



我不知道如何生成一个SALT。我想出了如何使用MessageDigest生成哈希。我尝试使用 SecureRandom ,但nextByte方法产生乱码。



编辑:我不知道哪个答案选择,对我来说太复杂了,我决定使用jBCrypt; jBCript很容易使用,所有复杂的东西都在幕后。所以我会让社区投票支持最佳答案。

解决方案

灵感来自这篇文章那篇文章,我使用这段代码生成和验证散列的盐渍密码。它只使用JDK提供的类,没有外部依赖。



过程是:




  • 你用 getNextSalt

  • 创建盐,你要求用户他的密码,并使用哈希
  • code>方法生成一个盐渍和散列的密码。该方法返回一个字节[] ,您可以使用盐
  • 在数据库中保存,以验证用户,您询问他的密码,从数据库中检索盐并散列密码,并使用 isExpectedPassword 方法来检查详细信息是否匹配





  / ** 
*用于哈希密码和检查密码的哈希值实用程序。它使用哈希和独特的
*盐的组合。所使用的算法是PBKDF2WithHmacSHA1,尽管不是最好的哈希密码(对比bcrypt)是
*仍然被认为是稳健的,< a href =https://security.stackexchange.com/a/6415/12614 >由NIST< / a>推荐。
*散列值有256位。
* /
public class Passwords {

private static final Random RANDOM = new SecureRandom();
private static final int ITERATIONS = 10000;
private static final int KEY_LENGTH = 256;

/ **
*静态实用程序类
* /
私人密码(){}

/ **
*返回用于哈希密码的随机盐。
*
* @返回一个16字节的随机盐
* /
public static byte [] getNextSalt(){
byte [] salt = new byte [16] ;
RANDOM.nextBytes(salt);
返回盐;
}

/ **
*使用提供的散列返回一个盐化和散列的密码。< br>
*注意 - 副作用:密码被破坏(char []填充为零)
*
* @param密码要加注的密码
* @param salt一个16字节的盐,理想情况下通过getNextSalt方法获得
*
* @返回带有一点盐的散列密码
* /
public static byte [] hash(char [ ] password,byte [] salt){
PBEKeySpec spec = new PBEKeySpec(password,salt,ITERATIONS,KEY_LENGTH);
Arrays.fill(password,Character.MIN_VALUE);
try {
SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2WithHmacSHA1);
return skf.generateSecret(spec).getEncoded();
} catch(NoSuchAlgorithmException | InvalidKeySpecException e){
throw new AssertionError(hashing a password:+ e.getMessage(),e);
} finally {
spec.clearPassword();
}
}

/ **
*如果给定的密码和salt与散列值匹配,则返回true,否则返回false< br>
*注意 - 副作用:密码被破坏(char []填充为零)
*
* @param密码检查
* @param salt盐用于哈希密码
* @param expectedHash预期的哈希值的密码
*
* @return如果给定的密码和salt匹配哈希值,则为true否则为
* /
public static boolean isExpectedPassword(char [] password,byte [] salt,byte [] expectedHash){
byte [] pwdHash = hash(password,salt);
Arrays.fill(password,Character.MIN_VALUE);
if(pwdHash.length!= expectedHash.length)return false; (int i = 0; i< pwdHash.length; i ++){
if(pwdHash [i]!= expectedHash [i])return false;
}
返回true;
}

/ **
*使用字母和数字生成给定长度的随机密码。
*
* @param长度的密码
*
* @返回随机密码
* /
public static String generateRandomPassword(int length ){
StringBuilder sb = new StringBuilder(length); (int i = 0; i< length; i ++)
{
int c = RANDOM.nextInt(62);
if(c <= 9){
sb.append(String.valueOf(c));
} else if(c< 36){
sb.append((char)('a'+ c - 10));
} else {
sb.append((char)('A'+ c - 36));
}
}
return sb.toString();
}
}


I've been looking around and the closest answer is : How to generate a random alpha-numeric string?

I want to follow this workflow according to this CrackStation tutorial:

To Store a Password

  1. Generate a long random salt using a CSPRNG.

  2. Prepend the salt to the password and hash it with a standard cryptographic hash function such as SHA256.

  3. Save both the salt and the hash in the user's database record.

To Validate a Password

  1. Retrieve the user's salt and hash from the database.

  2. Prepend the salt to the given password and hash it using the same hash function.

  3. Compare the hash of the given password with the hash from the database. If they match, the password is correct. Otherwise, the password is incorrect.

I don't know how to generate a SALT. I figured out how to generate a hash using the MessageDigest. I tried using SecureRandom but nextByte method produces garbled code.

Edit: I don't know which answer to choose, they're too complicated for me, I have decided to use jBCrypt; jBCript is easy to use, does all the complex stuff behind the scenes. so I'll let the community vote up for the best answer.

解决方案

Inspired from this post and that post, I use this code to generate and verify hashed salted passwords. It only uses JDK provided classes, no external dependency.

The process is:

  • you create a salt with getNextSalt
  • you ask the user his password and use the hash method to generate a salted and hashed password. The method returns a byte[] which you can save as is in a database with the salt
  • to authenticate a user, you ask his password, retrieve the salt and hashed password from the database and use the isExpectedPassword method to check that the details match

/**
 * A utility class to hash passwords and check passwords vs hashed values. It uses a combination of hashing and unique
 * salt. The algorithm used is PBKDF2WithHmacSHA1 which, although not the best for hashing password (vs. bcrypt) is
 * still considered robust and <a href="https://security.stackexchange.com/a/6415/12614"> recommended by NIST </a>.
 * The hashed value has 256 bits.
 */
public class Passwords {

  private static final Random RANDOM = new SecureRandom();
  private static final int ITERATIONS = 10000;
  private static final int KEY_LENGTH = 256;

  /**
   * static utility class
   */
  private Passwords() { }

  /**
   * Returns a random salt to be used to hash a password.
   *
   * @return a 16 bytes random salt
   */
  public static byte[] getNextSalt() {
    byte[] salt = new byte[16];
    RANDOM.nextBytes(salt);
    return salt;
  }

  /**
   * Returns a salted and hashed password using the provided hash.<br>
   * Note - side effect: the password is destroyed (the char[] is filled with zeros)
   *
   * @param password the password to be hashed
   * @param salt     a 16 bytes salt, ideally obtained with the getNextSalt method
   *
   * @return the hashed password with a pinch of salt
   */
  public static byte[] hash(char[] password, byte[] salt) {
    PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
    Arrays.fill(password, Character.MIN_VALUE);
    try {
      SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
      return skf.generateSecret(spec).getEncoded();
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
      throw new AssertionError("Error while hashing a password: " + e.getMessage(), e);
    } finally {
      spec.clearPassword();
    }
  }

  /**
   * Returns true if the given password and salt match the hashed value, false otherwise.<br>
   * Note - side effect: the password is destroyed (the char[] is filled with zeros)
   *
   * @param password     the password to check
   * @param salt         the salt used to hash the password
   * @param expectedHash the expected hashed value of the password
   *
   * @return true if the given password and salt match the hashed value, false otherwise
   */
  public static boolean isExpectedPassword(char[] password, byte[] salt, byte[] expectedHash) {
    byte[] pwdHash = hash(password, salt);
    Arrays.fill(password, Character.MIN_VALUE);
    if (pwdHash.length != expectedHash.length) return false;
    for (int i = 0; i < pwdHash.length; i++) {
      if (pwdHash[i] != expectedHash[i]) return false;
    }
    return true;
  }

  /**
   * Generates a random password of a given length, using letters and digits.
   *
   * @param length the length of the password
   *
   * @return a random password
   */
  public static String generateRandomPassword(int length) {
    StringBuilder sb = new StringBuilder(length);
    for (int i = 0; i < length; i++) {
      int c = RANDOM.nextInt(62);
      if (c <= 9) {
        sb.append(String.valueOf(c));
      } else if (c < 36) {
        sb.append((char) ('a' + c - 10));
      } else {
        sb.append((char) ('A' + c - 36));
      }
    }
    return sb.toString();
  }
}

这篇关于如何在Java中为Salted-Hash生成SALT?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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