200

I need to hash passwords for storage in a database. How can I do this in Java?

I was hoping to take the plain text password, add a random salt, then store the salt and the hashed password in the database.

Then when a user wanted to log in, I could take their submitted password, add the random salt from their account information, hash it and see if it equates to the stored hash password with their account information.

durron597
  • 31,968
  • 17
  • 99
  • 158
Chris Dutrow
  • 48,402
  • 65
  • 188
  • 258
  • Better to use the SHA family of hash functions. http://en.wikipedia.org/wiki/MD5 (although nothing is perfect) – YGL May 18 '10 at 21:03
  • 11
    @YGL this is actually not a recombination nowadays with GPU attacks being so cheap, SHA family is actually a very bad choice for password hashing (too fast) even with salt. Use bcrypt, scrypt or PBKDF2 – Eran Medan Nov 21 '12 at 07:01
  • 11
    Why was this question closed? This is a question for a real engineering problem, and the answers are invaluable. The OP is not asking for a library, he is asking how to solve the engineering problem. – stackoverflowuser2010 Apr 14 '15 at 05:23
  • 12
    Just amazing. This question has 52 upvotes, and someone decides to close it as "off-topic". – stackoverflowuser2010 Apr 14 '15 at 05:32
  • 1
    Yeah, I've posted on Meta about this issue of closings before, got beaten up pretty badly though. – Chris Dutrow Apr 14 '15 at 18:42
  • 9
    This question should be re-opened. It's a question about how to write a program to solve the problem described (password authentication), with a short code solution. Seeing the trigger word "library" doesn't justify reflexively closing a question; he's not asking for a library recommendation, he's asking how to hash passwords. Edit: There, fixed it. – erickson Jul 30 '15 at 13:36

14 Answers14

168

You can actually use a facility built in to the Java runtime to do this. The SunJCE in Java 6 supports PBKDF2, which is a good algorithm to use for password hashing.

SecureRandom random = new SecureRandom();
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));

Here's a utility class that you can use for PBKDF2 password authentication:

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);
  }

}
erickson
  • 265,237
  • 58
  • 395
  • 493
  • 12
    You may want to be a bit wary of byte to hex conversions with `BigInteger`: leading zeros are removed. That's ok for quick debug, but I have seen bugs in production code due to that effect. – Thomas Pornin May 19 '10 at 12:21
  • Thanks for this (+1). I'm constrained to Java 5. Is PBEWithHmacSHA1AndDESede a sufficiently strong algo? – Synesso Jan 21 '11 at 04:41
  • Yes, it's true that these salt and hash values should be treated as numbers, not strings, for repeatable results. – erickson Nov 21 '12 at 19:45
  • 24
    @thomas-pornin's highlights why we need a *library*, not a code block that's *almost* there. Scary that the accepted answer does not answer the question on such an important topic. – Nilzor Apr 24 '13 at 18:40
  • 10
    Use the algorithm PBKDF2WithHmacSHA512 starting with Java 8. It is a bit stronger. – iwan.z Nov 03 '14 at 13:05
  • @erickson I am nor very much into what the best algorithm is. But I checked what algorithms are available in which Java versions. Hope that helps: – iwan.z Nov 05 '14 at 06:12
  • 1
    Note, existing algs are not deleted in later versions: java_4:PBEWithMD5AndDES,DESede,DES java_5/6/7:PBKDF2WithHmacSHA1,PBE (only in 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 Nov 05 '14 at 06:26
  • @ThomasPornin Replaced hex by `BigInteger` with padded base-64. – erickson Jul 30 '15 at 13:45
  • @iwan.z In an HMAC, NIST suggests that SHA-1 will provide 128 bits of security, while SHA-224 or SHA-256 provide at least 192 and 256 bits, respectively. Match those algorithms with the AES key length you want to generate. Of course key derivation doesn't create entropy. It would be hard for a person to pick and remember a password for AES-256. – erickson Jul 30 '15 at 13:55
  • How we can compare two hash values with same SALT? Thanks, Neha –  Dec 29 '15 at 14:54
  • @erickson Is the password token to be stored on the server side or client side? – Errol Green Jun 13 '16 at 01:53
  • @ErrolGreen The token is stored at the server, and should be associated with the user identity. For example, a user table with id, login name and/or email address, and token. When someone logs in with login and password, lookup the stored token with the login and pass that to the `authenticate()` method with the password. – erickson Jun 13 '16 at 16:35
  • 2
    @erickson Sorry to dig up this post, but I spent some time analysing this code. I wonder why in method `authenticate(char[] password, String token) ` you changed `if` into `|=` operator? Is there any benefit in this? It looks like only effect will be longer execution time, or I miss something? – The Tosters Nov 22 '16 at 21:33
  • 5
    @TheTosters Yes, the execution time will be longer for *incorrect* passwords; more specifically, wrong passwords will take the same time as correct passwords. It prevents [timing attacks,](https://en.wikipedia.org/wiki/Timing_attack) although I confess I can't think of a practical way to exploit such a vulnerability in this case. But you don't cut corners. Just because I can't see it, doesn't mean a more devious mind won't. – erickson Nov 22 '16 at 21:40
  • @TheTosters using short-circuit comparison will make it faster, but also make movie-style password cracks possible. The attacker will be able to crack the password one character at a time by observing the time difference in failed auths. This attack is practical on real systems. Time difference is only one example of an oracle permitting faster cryptanalysis. Use validated cryptosystems unmodified and read their usage docs carefully to be confident that you aren’t accidentally breaking them. – Alain O'Dea Nov 25 '17 at 15:37
  • 1
    @erickson Upvotes for you sir and thanks for your patience! I drew boxes as you said, if we copy salt from 0 to salt.length (0 to 1), we copy the byte in hash[0] position. Then we copy dk from salt.length to dk.length - 1 to dk.length we get a correct copy. The base-64 encoding threw me off. When I print the encoded versions, the last char of the salt is gone unless I do +1. With +1 and hash one byte longer: dk: RA, salt: Qw, hash: QwBE. Without +1: and hash one byte smaller: dk: RA, salt: Qw, hash: Q0Q. But we don't need to see Qw and base64 encodes RA and Qw to Q0Q. Cheers and thanks! – Boris Dec 11 '17 at 04:56
  • 1
    @Boris That's it. With base-64, each character represents 6 bits of input, so each input byte is sort of smeared out over *two* characters in the output. Adding one byte of input will either add two characters to the output length (the first byte of a "block"), or modify the last character and add one more (the second and third bytes of a block). But each bit has its place and nothing is lost. – erickson Dec 11 '17 at 08:13
  • Sir, thanks for this example, can I have a question.. I dont know how to use this class. I first hash password using hash() method, and store it in database with login. Then every time user visits page and wants log in, I use authenticate() method, with input password and hash stored in database.. However every time authenticate() method returns false.. – 10101101 Mar 16 '20 at 10:13
  • 1
    @10101101 It sounds like you are using it correctly. Can you give an example of a password and the corresponding hash? In addition, here is a sample password and token that you can use for testing: `1ixrvSfjhPqd` / `$31$16$VKx6w7TTTyO8H504Ajxk6BOW034fSyZYhuayMVsf2P8`. Try storing that token in your database and see if you can login then. If so, it suggests that your enrollment process is broken. Of course, if you set that password on an account, the stored token will be different, since a different salt will be used. – erickson Mar 16 '20 at 19:21
  • @erickson Thanks for help, manually write that token to database, and when input provided password in login, unfortunately same result – 10101101 Mar 16 '20 at 19:39
  • 1
    @10101101 Okay. Do you have a test password and hash for me to test? – erickson Mar 16 '20 at 19:42
  • @erickson Yes, for example this hash: $31$16$AAnNmTEJQ98dQit8fyv-mMsGul7TFDGXMvE8IgzwqXg , and this password: haslo , I also tried same password with this hash: $31$16$ztuLbvMZjaDgmlsv1gttVZUiLNzvz8uVxb7YcIHpK2o – 10101101 Mar 16 '20 at 19:48
  • 1
    @10101101 The `authenticate()` method returns `true` when I pass `haslo` for a password and each of those hashes. Examine the value of your inputs and outputs right at the method, with a debugger or log statements (but don't log passwords in a production system). It looks like something is wrong downstream from the `authenticate()` call. – erickson Mar 16 '20 at 21:37
  • @erickson Yes Sir it works :D I dont know what happend, I didnt changed anything in code, only added some system outs prints.. and the next day it suddenly started working! Thank You from a bottom of my heart. – 10101101 Mar 19 '20 at 19:15
  • What is `random` defined on line 2 of first code block in provided answer? When you provide an answer, could you please elaborate on what you are doing? – Barrosy Dec 11 '22 at 16:11
  • 1
    @Barrosy That is meant as a snippet, with a detailed explanation in as following code. Your comment was helpful, but your edit introduced a potential vulnerability by using `Random` in place of `SecureRandom`, as demonstrated in the complete example. – erickson Dec 12 '22 at 17:26
30

BCrypt is a very good library, and there is a Java port of it.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
12

You could use Spring Security Crypto (has only 2 optional compile dependencies), which supports PBKDF2, BCrypt, SCrypt and Argon2 password encryption.

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);
BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
9

You can comput hashes using MessageDigest, but this is wrong in terms of security. Hashes are not to be used for storing passwords, as they are easily breakable.

You should use another algorithm like bcrypt, PBKDF2 and scrypt to store you passwords. See here.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 3
    How would you hash the password at login without storing salt in database? – ZZ Coder May 18 '10 at 20:43
  • 9
    Using the username as the salt is not a fatal flaw, but it's nowhere near as good as using a salt from a cryptographic RNG. And there is absolutely no problem storing the salt in the database. The salt is not secret. – erickson May 18 '10 at 20:44
  • 1
    Wouldn't the username and e-mail also be stored in the database? – Chris Dutrow May 18 '10 at 20:47
  • @ZZ Coder, @erickson correct, I somehow assumed that it will be one salt for all passwords, which would lead to an easily computable rainbow table. – Bozho May 18 '10 at 21:12
  • 14
    One problem with using the username (or other ID like email) as a salt is that you can't then change the ID without having the user also set a new password. – Lawrence Dol May 19 '10 at 02:37
  • Bad idea, you need a salt and work factor. Both are missing from this "protocol". – Maarten Bodewes Sep 09 '15 at 23:06
  • @MaartenBodewes agreed. Changing the answer – Bozho Oct 13 '15 at 15:09
  • @erickson `The salt is not secret` if salt is not a secret, wouldn't an attacker who steals the password also steal the salt and simply concatenate it to all passwords that he guesses? What kind of security does the salt add to the whole processes? Please help me understand. – qualebs Jul 18 '17 at 19:44
7

You can use the Shiro library's (formerly JSecurity) implementation of what is described by OWASP.

It also looks like the JASYPT library has a similar utility.

laz
  • 28,320
  • 5
  • 53
  • 50
  • Thats actually what I was using. But since we decided not to use Shiro, there was some concern about the inefficiency of having to include the whole Shiro library for just that one package. – Chris Dutrow May 18 '10 at 21:15
  • I don't know of a library made up of just a password hashing utility. You're probably better off rolling your own if dependencies are a concern. The answer by erickson looks pretty good to me. Or just copy the code from that OWASP link I referenced if you'd rather use SHA in a secure manner. – laz May 18 '10 at 21:26
6

Fully agree with Erickson that PBKDF2 is the answer.

If you don't have that option, or only need to use a hash, Apache Commons DigestUtils is much easier than getting JCE code right: https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html

If you use a hash, go with sha256 or sha512. This page has good recommendations on password handling and hashing (note it doesn't recommend hashing for password handling): http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html

Community
  • 1
  • 1
David Carboni
  • 1,556
  • 23
  • 24
  • it's worth noting that SHA512 isn't better than SHA256 (for this purpose) just because the number is bigger. – Azsgy Mar 27 '19 at 15:51
6

In addition to bcrypt and PBKDF2 mentioned in other answers, I would recommend looking at scrypt

MD5 and SHA-1 are not recommended as they are relatively fast thus using "rent per hour" distributed computing (e.g. EC2) or a modern high end GPU one can "crack" passwords using brute force / dictionary attacks in relatively low costs and reasonable time.

If you must use them, then at least iterate the algorithm a predefined significant amount of times (1000+).

Community
  • 1
  • 1
Eran Medan
  • 44,555
  • 61
  • 184
  • 276
6

While the NIST recommendation PBKDF2 has already been mentioned, I'd like to point out that there was a public password hashing competition that ran from 2013 to 2015. In the end, Argon2 was chosen as the recommended password hashing function.

There is a fairly well adopted Java binding for the original (native C) library that you can use.

In the average use-case, I don't think it does matter from a security perspective if you choose PBKDF2 over Argon2 or vice-versa. If you have strong security requirements, I recommend considering Argon2 in your evaluation.

For further information on the security of password hashing functions see security.se.

Qw3ry
  • 1,319
  • 15
  • 31
  • @zaph I edited the answer to be more objective. Please be aware that the NIST recommendation may not always be the best choice (see [here](https://en.wikipedia.org/wiki/National_Institute_of_Standards_and_Technology#Controversial_Backdoored_NIST_Standard) for an example) - of course this is true for anything that is recommended somewhere else as well. Therefore I do think this answer provides a value to this question. – Qw3ry Jul 05 '17 at 10:37
5

As of 2020, the most reliable password hashing algorithm in use, most likely to optimise its strength given any hardware, is Argon2id or Argon2i but not its Spring implementation.

The PBKDF2 standard includes the the CPU-greedy/computationally-expensive feature of the block cipher BCRYPT algo, and add its stream cipher capability. PBKDF2 was overwhelmed by the memory exponentially-greedy SCRYPT then by the side-channel-attack-resistant Argon2

Argon2 provides the necessary calibration tool to find optimized strength parameters given a target hashing time and the hardware used.

  • Argon2i is specialized in memory greedy hashing
  • Argon2d is specialized in CPU greedy hashing
  • Argon2id use both methods.

Memory greedy hashing would help against GPU use for cracking.

Spring security/Bouncy Castle implementation is not optimized and relatively week given what attacker could use. cf: Spring doc Argon2 and Scrypt

The currently implementation uses Bouncy castle which does not exploit parallelism/optimizations that password crackers will, so there is an unnecessary asymmetry between attacker and defender.

The most credible implementation in use for java is mkammerer's one,

a wrapper jar/library of the official native implementation written in C.

It is well written and simple to use.

The embedded version provides native builds for Linux, windows and OSX.

As an example, it is used by jpmorganchase in its tessera security project used to secure Quorum, its Ethereum cryptocurency implementation.

Here is an example:

    final char[] password = "a4e9y2tr0ngAnd7on6P১M°RD".toCharArray();
    byte[] salt = new byte[128];
    new SecureRandom().nextBytes(salt);
    final Argon2Advanced argon2 = Argon2Factory.createAdvanced(Argon2Factory.Argon2Types.ARGON2id);
    byte[] hash = argon2.rawHash(10, 1048576, 4, password, salt);

(see tessera)

Declare the lib in your POM:

<dependency>
    <groupId>de.mkammerer</groupId>
    <artifactId>argon2-jvm</artifactId>
    <version>2.7</version>
</dependency>

or with gradle:

compile 'de.mkammerer:argon2-jvm:2.7'

Calibration may be performed using de.mkammerer.argon2.Argon2Helper#findIterations

SCRYPT and Pbkdf2 algorithm might also be calibrated by writing some simple benchmark, but current minimal safe iterations values, will require higher hashing times.

user1767316
  • 3,276
  • 3
  • 37
  • 46
3

Here you have two links for MD5 hashing and other hash methods:

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

Tutorial: http://www.twmacinta.com/myjava/fast_md5.php

fospathi
  • 537
  • 1
  • 6
  • 7
Simon
  • 9,255
  • 4
  • 37
  • 54
  • 3
    Just keep in mind that for password hashing, slower is better. You should use thousands of iterations of the hash function as a "key strengthening" technique. Also, salt is imperative. – erickson May 18 '10 at 21:08
  • I was under the impression that multiple iterations of a quality hashing algorithm would produce about the same security as one iteration since the length of bytes would still be the same? – Chris Dutrow May 18 '10 at 21:17
  • @erickson It would be better to slow down attackers explicitly. – deamon May 18 '10 at 21:18
  • Yeah, but hashing the hashe's hash ..., is more secure. Let's say you hash "a" to "b" and "b" to "c". Someone could be able to get somehow (though not uniquely) the value "b" but he will unlikely get the original value "a" as he does not know how many times you hashed your intial value. – Simon May 18 '10 at 21:20
  • @deamon - "Slow them down explicitly?" What does that mean? – erickson May 18 '10 at 21:24
  • 6
    About key strengthening: Salts exist to make precomputed hashes unusable. But attackers do not have to precompute. Attackers can just hash strings + salt "on the fly" until they find the right one. But if you iterate thousands of times for your hashes they will have to do the same. Your server will not be impacted much by 10k iterations as it doesn't happen that often. Attackers will need 10k times the computing power. – zckman May 19 '10 at 06:26
  • 2
    @Simon today MD5 is considered useless for password hashing as it can be cracked in seconds using GPU brute force / dictionary attacks. See here: http://codahale.com/how-to-safely-store-a-password/ – Eran Medan Nov 21 '12 at 07:27
  • @zockman you have demystified a concept that had me puzzled ever since I first heard salt and hashing in one sentence. Makes much sense now thanks. +1 – qualebs Jul 18 '17 at 19:51
1

Among all the standard hash schemes, LDAP ssha is the most secure one to use,

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

I would just follow the algorithms specified there and use MessageDigest to do the hash.

You need to store the salt in your database as you suggested.

ZZ Coder
  • 74,484
  • 29
  • 137
  • 169
  • 1
    Because SSHA doesn't iterate the hash function, it is too fast. This allows attackers to try passwords more quickly. Better algorithms like Bcrypt, PBBKDF1, and PBKDF2 use "key strengthening" techniques to slow attackers to the point where a password should expire before they can brute force even an 8-letter password space. – erickson May 18 '10 at 21:14
  • The problem with all these mechanisms is that you don't get client support. The problem with hashed password is that you can't support password hashed with another algorithms. With ssha, at least all the LDAP clients support it. – ZZ Coder May 18 '10 at 21:19
  • It is not "most secure" it is merely "pretty compatible". bcrypt/scrypt are way more ressource intensitive. – eckes Nov 22 '12 at 16:44
0

i leaned that from a video on udemy and edited to be stronger random password

}

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);
}






}
  • 1
    I'm open to being corrected, but I think you shouldn't use random numbers when hashing. This is so that your hash function remains deterministic; that is if you hash a string multiple times you will always get the same hash value back for that string. – duldi Jun 06 '20 at 01:29
0

Here is my simple PasswordHasher class that I made:

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;

public class PasswordHasher {
    private static final String ALGO = "PBKDF2WithHmacSHA1";
    private static final byte[] SALT = {
            8, 8, 8, 8, 2,
            8, 7, 7, 7, 2,
            1, 1, 1, 1, 2,
            11
    };
    private static final int ITERATION_COUNT = 1000;
    private static final int KEY_LENGTH = 128;

    private SecretKeyFactory mFactory;

    byte[] hashPassword(String password) {
        SecretKeyFactory factory = getFactory();

        if (factory != null) {
            try {
                KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, ITERATION_COUNT, KEY_LENGTH);
                return factory.generateSecret(spec).getEncoded();
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    boolean verifyPassword(String password, byte[] expectedHashResult) {
        byte[] hashedPassword = hashPassword(password);
        if (hashedPassword == null) {
            // Log fail result
            return false;
        }
        return Arrays.equals(hashedPassword, expectedHashResult);
    }

    private SecretKeyFactory getFactory() {
        if (mFactory == null) {
            try {
                mFactory = SecretKeyFactory.getInstance(ALGO);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        return mFactory;
    }
}
Quốc Hùng
  • 106
  • 1
  • 7
0
import java.security.MessageDigest;
import javax.mail.*;
import javax.mail.internet.*;
import java.util.Base64;
import java.util.Properties;
public class Main{
    public static void main(String[]a]{
    
//enter code here

}
   
    public static String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] hash = md.digest(password.getBytes());
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

hashPassword is the method that returns a hashed value when we pass a String as its parameter. MessageDigest is the class that provides the interface for hashing password getInstance is used to get the instance of a hashing algorithm such as MD-5,SHA 216,SHA-512 and so on. The hashed Sting is in the forn of -byte [] In the return statement we convert the byte using ToString.

pt7092
  • 11
  • 2