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

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

问题描述

我环顾四周,最接近的答案是:How生成一个随机的字母数字字符串?

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

我想根据这个CrackStation教程来遵循这个工作流程:

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

存储密码

  1. 使用 CSPRNG 生成长随机盐.

  1. Generate a long random salt using a CSPRNG.

在密码前添加盐并使用标准加密哈希函数(如 SHA256)对其进行哈希处理.

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

在用户的数据库记录中保存盐和哈希值.

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

验证密码

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

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

在给定的密码前添加盐并使用相同的散列函数散列它.

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

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

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.

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

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.

我不知道该选择哪个答案,它们对我来说太复杂了,我决定使用 jBCrypt;jBCript 易于使用,可以在幕后完成所有复杂的工作.所以我会让社区投票选出最佳答案.

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.

推荐答案

灵感来自 这篇文章该帖子,我使用此代码生成和验证散列加盐密码.它只使用JDK提供的类,没有外部依赖.

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.

流程是:

  • 你用 getNextSalt
  • 创建了一个盐
  • 您询问用户他的密码并使用 hash 方法生成一个加盐和散列的密码.该方法返回一个 byte[],您可以将其保存在带有盐的数据库中
  • 要对用户进行身份验证,您需要询问他的密码,从数据库中检索盐和散列密码,然后使用 isExpectedPassword 方法检查详细信息是否匹配
  • 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天全站免登陆