Làm cách nào để băm mật khẩu trong Java?


176

Tôi cần băm mật khẩu để lưu trữ trong cơ sở dữ liệu. Làm thế nào tôi có thể làm điều này trong Java?

Tôi đã hy vọng lấy mật khẩu văn bản đơn giản, thêm một muối ngẫu nhiên, sau đó lưu trữ muối và mật khẩu băm trong cơ sở dữ liệu.

Sau đó, khi người dùng muốn đăng nhập, tôi có thể lấy mật khẩu đã gửi của họ, thêm muối ngẫu nhiên từ thông tin tài khoản của họ, băm nó và xem liệu nó có tương đương với mật khẩu băm được lưu trữ với thông tin tài khoản của họ không.


11
@YGL đây thực sự không phải là sự tái hợp hiện nay với các cuộc tấn công GPU quá rẻ, gia đình SHA thực sự là một lựa chọn rất tệ cho việc băm mật khẩu (quá nhanh) ngay cả với muối. Sử dụng bcrypt, scrypt hoặc PBKDF2
Eran Medan

11
Tại sao câu hỏi này được đóng lại? Đây là một câu hỏi cho một vấn đề kỹ thuật thực sự, và câu trả lời là vô giá. OP không yêu cầu một thư viện, anh ấy đang hỏi làm thế nào để giải quyết vấn đề kỹ thuật.
stackoverflowuser2010

12
Thật tuyệt vời. Câu hỏi này có 52 câu hỏi và ai đó quyết định đóng nó dưới dạng "lạc đề".
stackoverflowuser2010

1
Vâng, tôi đã đăng trên Meta về vấn đề đóng cửa này trước đây, mặc dù đã bị đánh đập khá tệ.
Chris Dutrow

8
Câu hỏi này nên được mở lại. Đó là một câu hỏi về cách viết chương trình để giải quyết vấn đề được mô tả (xác thực mật khẩu), với một giải pháp mã ngắn. Nhìn thấy từ kích hoạt "thư viện" không thể biện minh cho việc đóng câu hỏi theo phản xạ; Anh ấy không yêu cầu đề xuất thư viện, anh ấy hỏi cách băm mật khẩu. Chỉnh sửa: Có, sửa nó.
erickson

Câu trả lời:


157

Bạn thực sự có thể sử dụng một phương tiện được tích hợp sẵn trong thời gian chạy Java để làm điều này. SunJCE trong Java 6 hỗ trợ PBKDF2, đây là một thuật toán tốt để sử dụng để băm mật khẩu.

byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 128);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
System.out.printf("salt: %s%n", enc.encodeToString(salt));
System.out.printf("hash: %s%n", enc.encodeToString(hash));

Đây là một lớp tiện ích mà bạn có thể sử dụng để xác thực mật khẩu PBKDF2:

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

/**
 * Hash passwords for storage, and test passwords against password tokens.
 * 
 * Instances of this class can be used concurrently by multiple threads.
 *  
 * @author erickson
 * @see <a href="http://stackoverflow.com/a/2861125/3474">StackOverflow</a>
 */
public final class PasswordAuthentication
{

  /**
   * Each token produced by this class uses this identifier as a prefix.
   */
  public static final String ID = "$31$";

  /**
   * The minimum recommended cost, used by default
   */
  public static final int DEFAULT_COST = 16;

  private static final String ALGORITHM = "PBKDF2WithHmacSHA1";

  private static final int SIZE = 128;

  private static final Pattern layout = Pattern.compile("\\$31\\$(\\d\\d?)\\$(.{43})");

  private final SecureRandom random;

  private final int cost;

  public PasswordAuthentication()
  {
    this(DEFAULT_COST);
  }

  /**
   * Create a password manager with a specified cost
   * 
   * @param cost the exponential computational cost of hashing a password, 0 to 30
   */
  public PasswordAuthentication(int cost)
  {
    iterations(cost); /* Validate cost */
    this.cost = cost;
    this.random = new SecureRandom();
  }

  private static int iterations(int cost)
  {
    if ((cost < 0) || (cost > 30))
      throw new IllegalArgumentException("cost: " + cost);
    return 1 << cost;
  }

  /**
   * Hash a password for storage.
   * 
   * @return a secure authentication token to be stored for later authentication 
   */
  public String hash(char[] password)
  {
    byte[] salt = new byte[SIZE / 8];
    random.nextBytes(salt);
    byte[] dk = pbkdf2(password, salt, 1 << cost);
    byte[] hash = new byte[salt.length + dk.length];
    System.arraycopy(salt, 0, hash, 0, salt.length);
    System.arraycopy(dk, 0, hash, salt.length, dk.length);
    Base64.Encoder enc = Base64.getUrlEncoder().withoutPadding();
    return ID + cost + '$' + enc.encodeToString(hash);
  }

  /**
   * Authenticate with a password and a stored password token.
   * 
   * @return true if the password and token match
   */
  public boolean authenticate(char[] password, String token)
  {
    Matcher m = layout.matcher(token);
    if (!m.matches())
      throw new IllegalArgumentException("Invalid token format");
    int iterations = iterations(Integer.parseInt(m.group(1)));
    byte[] hash = Base64.getUrlDecoder().decode(m.group(2));
    byte[] salt = Arrays.copyOfRange(hash, 0, SIZE / 8);
    byte[] check = pbkdf2(password, salt, iterations);
    int zero = 0;
    for (int idx = 0; idx < check.length; ++idx)
      zero |= hash[salt.length + idx] ^ check[idx];
    return zero == 0;
  }

  private static byte[] pbkdf2(char[] password, byte[] salt, int iterations)
  {
    KeySpec spec = new PBEKeySpec(password, salt, iterations, SIZE);
    try {
      SecretKeyFactory f = SecretKeyFactory.getInstance(ALGORITHM);
      return f.generateSecret(spec).getEncoded();
    }
    catch (NoSuchAlgorithmException ex) {
      throw new IllegalStateException("Missing algorithm: " + ALGORITHM, ex);
    }
    catch (InvalidKeySpecException ex) {
      throw new IllegalStateException("Invalid SecretKeyFactory", ex);
    }
  }

  /**
   * Hash a password in an immutable {@code String}. 
   * 
   * <p>Passwords should be stored in a {@code char[]} so that it can be filled 
   * with zeros after use instead of lingering on the heap and elsewhere.
   * 
   * @deprecated Use {@link #hash(char[])} instead
   */
  @Deprecated
  public String hash(String password)
  {
    return hash(password.toCharArray());
  }

  /**
   * Authenticate with a password in an immutable {@code String} and a stored 
   * password token. 
   * 
   * @deprecated Use {@link #authenticate(char[],String)} instead.
   * @see #hash(String)
   */
  @Deprecated
  public boolean authenticate(String password, String token)
  {
    return authenticate(password.toCharArray(), token);
  }

}

11
Bạn có thể muốn cảnh giác một chút về chuyển đổi byte sang hex với BigInteger: các số 0 đứng đầu được loại bỏ. Điều đó ổn cho việc gỡ lỗi nhanh, nhưng tôi đã thấy các lỗi trong mã sản xuất do hiệu ứng đó.
Thomas Pornin

24
@ thomas-pornin nhấn mạnh lý do tại sao chúng ta cần một thư viện , không phải là một khối mã gần như ở đó. Đáng sợ rằng câu trả lời được chấp nhận không trả lời câu hỏi về một chủ đề quan trọng như vậy.
Nilzor

9
Sử dụng thuật toán PBKDF2WithHmacSHA512 bắt đầu với Java 8. Nó mạnh hơn một chút.
iwan.z

1
Lưu ý, algs hiện sẽ không bị xóa trong các phiên bản sau: java_4: PBEWithMD5AndDES, DESede, DES java_5 / 6/7: PBKDF2WithHmacSHA1, PBE (chỉ trong Java 5), PBEWithSHA1AndRC2_40, PBEWithSHA1And, PBEWithMD5AndTriple java_8: PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA512AndAES_128, RC4_40, PBKDF2WithHmacSHA256 , PBEWithHmacSHA1AndAES_128, RC4_128, PBKDF2WithHmacSHA224, PBEWithHmacSHA256AndAES_256, RC2_128, PBEWithHmacSHA224AndAES_256, PBEWithHmacSHA384AndAES_256, PBEWithHmacSHA512AndAES_256, PBKDF2WithHmacSHA512, PBEWithHmacSHA256AndAES_128, PBKDF2WithHmacSHA384, PBEWithHmacSHA1AndAES_256
iwan.z

4
@TheTosters Có, thời gian thực hiện sẽ lâu hơn đối với mật khẩu không chính xác ; cụ thể hơn, mật khẩu sai sẽ mất cùng thời gian với mật khẩu chính xác. Nó ngăn chặn các cuộc tấn công thời gian, mặc dù tôi thú nhận rằng tôi không thể nghĩ ra một cách thực tế để khai thác lỗ hổng như vậy trong trường hợp này. Nhưng bạn không cắt góc. Chỉ vì tôi không thể nhìn thấy nó, không có nghĩa là một tâm trí quỷ quyệt hơn sẽ không.
erickson

97

Đây là một triển khai hoàn chỉnh với hai phương thức thực hiện chính xác những gì bạn muốn:

String getSaltedHash(String password)
boolean checkPassword(String password, String stored)

Vấn đề là ngay cả khi kẻ tấn công có quyền truy cập vào cả cơ sở dữ liệu và mã nguồn của bạn, mật khẩu vẫn an toàn.

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;

public class Password {
    // The higher the number of iterations the more 
    // expensive computing the hash is for us and
    // also for an attacker.
    private static final int iterations = 20*1000;
    private static final int saltLen = 32;
    private static final int desiredKeyLen = 256;

    /** Computes a salted PBKDF2 hash of given plaintext password
        suitable for storing in a database. 
        Empty passwords are not supported. */
    public static String getSaltedHash(String password) throws Exception {
        byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen);
        // store the salt with the password
        return Base64.encodeBase64String(salt) + "$" + hash(password, salt);
    }

    /** Checks whether given plaintext password corresponds 
        to a stored salted hash of the password. */
    public static boolean check(String password, String stored) throws Exception{
        String[] saltAndHash = stored.split("\\$");
        if (saltAndHash.length != 2) {
            throw new IllegalStateException(
                "The stored password must have the form 'salt$hash'");
        }
        String hashOfInput = hash(password, Base64.decodeBase64(saltAndHash[0]));
        return hashOfInput.equals(saltAndHash[1]);
    }

    // using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt
    // cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html
    private static String hash(String password, byte[] salt) throws Exception {
        if (password == null || password.length() == 0)
            throw new IllegalArgumentException("Empty passwords are not supported.");
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        SecretKey key = f.generateSecret(new PBEKeySpec(
            password.toCharArray(), salt, iterations, desiredKeyLen));
        return Base64.encodeBase64String(key.getEncoded());
    }
}

Chúng tôi đang lưu trữ 'salt$iterated_hash(password, salt)'. Muối là 32 byte ngẫu nhiên và mục đích của nó là nếu hai người khác nhau chọn cùng một mật khẩu, mật khẩu được lưu trữ sẽ vẫn trông khác nhau.

Điều này iterated_hash, về cơ bản hash(hash(hash(... hash(password, salt) ...)))làm cho nó rất tốn kém cho một kẻ tấn công tiềm năng có quyền truy cập vào cơ sở dữ liệu của bạn để đoán mật khẩu, băm chúng và tìm kiếm băm trong cơ sở dữ liệu. Bạn phải tính toán điều này iterated_hashmỗi khi người dùng đăng nhập, nhưng nó không tốn của bạn nhiều so với kẻ tấn công dành gần 100% thời gian băm máy tính của họ.


14
Xin lỗi để cằn nhằn, nhưng tại sao tôi nên chọn cái này trên một thư viện hiện có? Một thư viện có thể có cơ hội cao hơn để được xem xét kỹ lưỡng. Tôi nghi ngờ rằng mỗi một trong số 14 phiếu bầu đã phân tích mã cho bất kỳ vấn đề nào.
Joachim Sauer

2
@JoachimSauer Đây thực chất chỉ là sử dụng thư viện (javax.crypto) nhưng bạn đã đúng - mật khẩu trống không được hỗ trợ. Đã thêm một ngoại lệ để làm cho nó rõ ràng. Cảm ơn!
Martin Konicek

3
Bạn có thể nên thay đổi chữ ký phương thức thành char[] passwordthay vì String password.
assylias

2
Mặc dù có vẻ như tài liệu tham khảo không nhận được sự nhất trí. Xem thêm điều này: security.stackexchange.com/a/20369/12614
assylias

3
Bạn có chắc chắn rằng .equals () trên các chuỗi không bị đoản mạch (nghĩa là: dừng lặp khi tìm thấy hai byte không bằng nhau)? Nếu nó có nguy cơ bị tấn công thời gian làm rò rỉ thông tin về mật khẩu băm.
bobpoekert


7

Bạn có thể sử dụng triển khai của thư viện Shiro (trước đây là Bảo mật ) về những gì được mô tả bởi OWASP .

Dường như thư viện JASYPT có một tiện ích tương tự .


Đó thực sự là những gì tôi đã sử dụng. Nhưng vì chúng tôi quyết định không sử dụng Shiro, nên có một số lo ngại về việc không hiệu quả khi phải bao gồm toàn bộ thư viện Shiro cho chỉ một gói đó.
Chris Dutrow

Tôi không biết về một thư viện được tạo thành từ một tiện ích băm mật khẩu. Có lẽ bạn nên tự lăn lộn nếu sự phụ thuộc là một mối quan tâm. Câu trả lời của erickson có vẻ khá tốt với tôi. Hoặc chỉ sao chép mã từ liên kết OWASP mà tôi đã tham chiếu nếu bạn muốn sử dụng SHA một cách an toàn.
laz

7

Bạn có thể tính toán băm bằng cách sử dụng MessageDigest, nhưng điều này là sai về mặt bảo mật. Băm không được sử dụng để lưu trữ mật khẩu, vì chúng rất dễ bị phá vỡ.

Bạn nên sử dụng một thuật toán khác như bcrypt, PBKDF2 và scrypt để lưu trữ mật khẩu của bạn. Xem ở đây .


3
Làm thế nào bạn sẽ băm mật khẩu khi đăng nhập mà không lưu trữ muối trong cơ sở dữ liệu?
ZZ

9
Sử dụng tên người dùng làm muối không phải là một lỗ hổng chết người, nhưng không nơi nào tốt bằng việc sử dụng muối từ RNG mật mã. Và hoàn toàn không có vấn đề lưu trữ muối trong cơ sở dữ liệu. Muối không bí mật.
erickson

1
Tên người dùng và e-mail cũng sẽ không được lưu trữ trong cơ sở dữ liệu chứ?
Chris Dutrow

@ZZ Coder, @erickson chính xác, bằng cách nào đó tôi đã giả định rằng nó sẽ là một muối cho tất cả mật khẩu, điều này sẽ dẫn đến một bảng cầu vồng dễ tính toán.
Bozho

13
Một vấn đề với việc sử dụng tên người dùng (hoặc ID khác như email) làm muối là bạn không thể thay đổi ID mà không cần người dùng cũng đặt mật khẩu mới.
Lawrence Dol

6

Ngoài bcrypt và PBKDF2 được đề cập trong các câu trả lời khác, tôi khuyên bạn nên xem xét về tiền điện tử

MD5 và SHA-1 không được khuyến nghị vì chúng tương đối nhanh, do đó sử dụng máy tính phân tán "thuê mỗi giờ" (ví dụ EC2) hoặc GPU cao cấp hiện đại, người ta có thể "bẻ khóa" mật khẩu bằng cách sử dụng tấn công từ điển / mạnh mẽ với chi phí tương đối thấp và hợp lý thời gian.

Nếu bạn phải sử dụng chúng, thì ít nhất hãy lặp lại thuật toán một số lần đáng kể được xác định trước (1000+).


6

Hoàn toàn đồng ý với Erickson rằng PBKDF2 là câu trả lời.

Nếu bạn không có tùy chọn đó hoặc chỉ cần sử dụng hàm băm, Apache Commons DigestUtils dễ dàng hơn nhiều so với việc lấy mã JCE ngay: https://commons.apache.org/proper/commons-codec/apidocs/org/apache /commons/codec/digest/DigestUtils.html

Nếu bạn sử dụng hàm băm, hãy sử dụng sha256 hoặc sha512. Trang này có các đề xuất tốt về xử lý mật khẩu và băm (lưu ý không khuyến nghị băm để xử lý mật khẩu): http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html


Điều đáng chú ý là SHA512 không tốt hơn SHA256 (cho mục đích này) chỉ vì số lượng lớn hơn.
Azsgy

5

Bạn có thể sử dụng Spring Security Crypto (chỉ có 2 phụ thuộc biên dịch tùy chọn ), hỗ trợ mã hóa mật khẩu PBKDF2 , BCrypt , SCryptArgon2 .

Argon2PasswordEncoder argon2PasswordEncoder = new Argon2PasswordEncoder();
String aCryptedPassword = argon2PasswordEncoder.encode("password");
boolean passwordIsValid = argon2PasswordEncoder.matches("password", aCryptedPassword);
SCryptPasswordEncoder sCryptPasswordEncoder = new SCryptPasswordEncoder();
String sCryptedPassword = sCryptPasswordEncoder.encode("password");
boolean passwordIsValid = sCryptPasswordEncoder.matches("password", sCryptedPassword);
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String bCryptedPassword = bCryptPasswordEncoder.encode("password");
boolean passwordIsValid = bCryptPasswordEncoder.matches("password", bCryptedPassword);
Pbkdf2PasswordEncoder pbkdf2PasswordEncoder = new Pbkdf2PasswordEncoder();
String pbkdf2CryptedPassword = pbkdf2PasswordEncoder.encode("password");
boolean passwordIsValid = pbkdf2PasswordEncoder.matches("password", pbkdf2CryptedPassword);

4

Mặc dù đề xuất PBKDF2 của NIST đã được đề cập, tôi muốn chỉ ra rằng có một cuộc thi băm mật khẩu công khai diễn ra từ năm 2013 đến 2015. Cuối cùng, Argon2 đã được chọn làm chức năng băm mật khẩu được đề xuất.

Có một ràng buộc Java được chấp nhận khá tốt cho thư viện gốc (C gốc) mà bạn có thể sử dụng.

Trong trường hợp sử dụng trung bình, tôi không nghĩ nó có vấn đề từ góc độ bảo mật nếu bạn chọn PBKDF2 thay vì Argon2 hoặc ngược lại. Nếu bạn có yêu cầu bảo mật mạnh mẽ, tôi khuyên bạn nên xem xét Argon2 trong đánh giá của mình.

Để biết thêm thông tin về bảo mật của các chức năng băm mật khẩu, xem security.se .


@zaph Mình chỉnh sửa câu trả lời để khách quan hơn. Xin lưu ý rằng khuyến nghị của NIST có thể không phải luôn luôn là lựa chọn tốt nhất (xem ví dụ ở đây ) - tất nhiên điều này đúng với bất cứ điều gì được đề xuất ở một nơi khác. Vì vậy, tôi nghĩ rằng câu trả lời này cung cấp một giá trị cho câu hỏi này.
Qw3ry

2

Ở đây bạn có hai liên kết để băm MD5 và các phương thức băm khác:

API Javadoc: https://docs.oracle.com/javase/1.5.0/docs/api/java/security/MessageDigest.html

Hướng dẫn: http://www.twmacinta.com/myjava/fast_md5.php


3
Chỉ cần nhớ rằng để băm mật khẩu, chậm hơn là tốt hơn. Bạn nên sử dụng hàng ngàn lần lặp của hàm băm như một kỹ thuật "tăng cường khóa". Ngoài ra, muối là bắt buộc.
erickson

Tôi có ấn tượng rằng nhiều lần lặp của thuật toán băm chất lượng sẽ tạo ra cùng một bảo mật như một lần lặp vì độ dài của byte vẫn giống nhau?
Chris Dutrow

@erickson Sẽ tốt hơn nếu làm chậm những kẻ tấn công một cách rõ ràng.
deamon

6
Về việc tăng cường khóa: Muối tồn tại để làm cho băm được tính toán trước không sử dụng được. Nhưng những kẻ tấn công không phải tính toán trước. Kẻ tấn công chỉ có thể băm chuỗi + muối "trên đường bay" cho đến khi chúng tìm thấy đúng. Nhưng nếu bạn lặp đi lặp lại hàng ngàn lần cho băm của bạn, họ sẽ phải làm như vậy. Máy chủ của bạn sẽ không bị ảnh hưởng nhiều bởi 10 lần lặp vì nó không xảy ra thường xuyên. Kẻ tấn công sẽ cần gấp 10k lần sức mạnh tính toán.
zockman

2
@Simon hôm nay MD5 được coi là vô dụng đối với việc băm mật khẩu vì nó có thể bị bẻ khóa trong vài giây bằng cách sử dụng các cuộc tấn công từ điển / sức mạnh của GPU. Xem tại đây: codahale.com/how-to-safely-store-a-password
Eran Medan

1

Trong số tất cả các lược đồ băm tiêu chuẩn, LDAP ssha là phương thức an toàn nhất để sử dụng,

http://www.openldap.org/faq/data/cache/347.html

Tôi sẽ chỉ làm theo các thuật toán được chỉ định ở đó và sử dụng MessageDigest để thực hiện băm.

Bạn cần lưu trữ muối trong cơ sở dữ liệu của bạn như bạn đề xuất.


1
Vì SSHA không lặp lại hàm băm, nên nó quá nhanh. Điều này cho phép kẻ tấn công thử mật khẩu nhanh hơn. Các thuật toán tốt hơn như Bcrypt, PBBKDF1 và PBKDF2 sử dụng các kỹ thuật "tăng cường khóa" để làm chậm kẻ tấn công đến mức mật khẩu sẽ hết hạn trước khi chúng có thể bắt buộc sử dụng không gian mật khẩu 8 ký tự.
erickson

Vấn đề với tất cả các cơ chế này là bạn không nhận được hỗ trợ khách hàng. Vấn đề với mật khẩu băm là bạn không thể hỗ trợ mật khẩu được băm bằng các thuật toán khác. Với ssha, ít nhất là tất cả các máy khách LDAP hỗ trợ nó.
ZZ

Nó không "an toàn nhất", nó chỉ đơn thuần là "khá tương thích". bcrypt / scrypt là cách mạnh mẽ hơn ressource.
eckes

1

Tính đến năm 2020, thuật toán đáng tin cậy và linh hoạt nhất được sử dụng,

một trong những khả năng tối ưu hóa sức mạnh của nó với bất kỳ phần cứng nào,

Argon2id hoặc Argon2i .

Nó cung cấp công cụ hiệu chuẩn cần thiết để tìm các tham số cường độ được tối ưu hóa theo thời gian băm mục tiêu và phần cứng được sử dụng.

  • Argon2i chuyên băm tham lam
  • Argon2d chuyên băm CPU
  • Argon2id sử dụng cả hai phương pháp.

Băm tham lam bộ nhớ sẽ giúp chống lại việc sử dụng GPU để bẻ khóa.

Bảo mật mùa xuân / Bouncy Castle không được tối ưu hóa và tương đối tuần cho những gì kẻ tấn công có thể sử dụng. cf: Tài liệu mùa xuân

Việc triển khai hiện tại sử dụng lâu đài Bouncy không khai thác song song / tối ưu hóa mà những kẻ bẻ khóa mật khẩu sẽ có, do đó có sự bất cân xứng không cần thiết giữa kẻ tấn công và kẻ phòng thủ.

Việc triển khai đáng tin cậy nhất được sử dụng cho java là của mkammerer ,

một thư viện / thư viện của bản triển khai chính thức được viết bằng Rust.

Nó được viết tốt và đơn giản để sử dụng.

Phiên bản nhúng cung cấp các bản dựng gốc cho Linux, windows và OSX.

Ví dụ, nó được jpmorganchase sử dụng trong dự án bảo mật tessera của nó được sử dụng để bảo mật Quorum , triển khai tiền điện tử Ethereum của nó.

Đây là mã ví dụ từ tessera.

Hiệu chuẩn có thể được thực hiện bằng de.mkammerer.argon2.Argon2Helper # findIterations

Thuật toán SCRYPT và Pbkdf2 cũng có thể được hiệu chỉnh bằng cách viết một số điểm chuẩn đơn giản, nhưng các giá trị lặp an toàn tối thiểu hiện tại, sẽ yêu cầu thời gian băm cao hơn.


0

tôi đã dựa vào video từ udemy và chỉnh sửa thành mật khẩu ngẫu nhiên mạnh hơn

}

private String pass() {
        String passswet="1234567890zxcvbbnmasdfghjklop[iuytrtewq@#$%^&*" ;

        char icon1;
        char[] t=new char[20];

         int rand1=(int)(Math.random()*6)+38;//to make a random within the range of special characters

            icon1=passswet.charAt(rand1);//will produce char with a special character

        int i=0;
        while( i <11) {

             int rand=(int)(Math.random()*passswet.length());
             //notice (int) as the original value of Math>random() is double

             t[i] =passswet.charAt(rand);

             i++;
                t[10]=icon1;
//to replace the specified item with icon1
         }
        return new String(t);
}






}

Tôi sẵn sàng để được sửa chữa, nhưng tôi nghĩ bạn không nên sử dụng các số ngẫu nhiên khi băm. Điều này là để hàm băm của bạn vẫn mang tính quyết định; đó là nếu bạn băm một chuỗi nhiều lần, bạn sẽ luôn nhận được cùng một giá trị băm cho chuỗi đó.
duldi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.