google / guava

Google core libraries for Java
Apache License 2.0
50.07k stars 10.86k forks source link

Multiple hash iterations #831

Closed gissuebot closed 9 years ago

gissuebot commented 9 years ago

Original issue created by toellrich on 2011-12-22 at 05:59 AM


Once issue 830 is fixed, I intend to use Guavas Hashing API for creating password hashes. At the moment, the code would look something like this:

public static String encodePassword(String password, String salt) {   HashFunction func = Hashing.sha256();   HashCode result = func.hashString(password + salt, UTF_8);   for (int i = 0; i < ITERATION_COUNT; i++) {     result = func.hashBytes(result.asBytes());   }   return salt + result.toString(); }

I was wondering if the possibility of hashing a hash n times could be added to the API? Also, a salt generator that generates random hexadecimal values of a given length would be very useful.

gissuebot commented 9 years ago

Original comment posted by wasserman.louis on 2011-12-22 at 05:59 PM


I suspect that your "salt generator" would be adequately implemented by SecureRandom...no?

gissuebot commented 9 years ago

Original comment posted by toellrich on 2011-12-22 at 06:10 PM


Absolutely. I currently use the following code to generate salts that are 10 chars long, but the length should probably be configurable.

private static final SecureRandom random = new SecureRandom(); private static final int SALT_LENGTH = 10;

public static String getRandomSalt() {   String randomHexString = new BigInteger(40, random).toString(16);   String result = Strings.padStart(randomHexString, SALT_LENGTH, '0');   assert result.length() == SALT_LENGTH;   return result; }

gissuebot commented 9 years ago

Original comment posted by wasserman.louis on 2011-12-22 at 06:20 PM


I was assuming you'd be interested in salt as a byte[], which is the form I'd expect you to actually end up using? And a SecureRandom lets you just do nextBytes(byte[]).

gissuebot commented 9 years ago

Original comment posted by toellrich on 2011-12-22 at 08:43 PM


I have to store the salt as well as the password hash at some point in the database and the last time I checked, Hibernate's/Oracle's support for byte arrays was a bit iffy. Therefore, i decided to simply convert everything to String.

By the way, I've created a utility class for creating secure password hashes:

http://pastebin.com/T8yUi72S

Please feel free to reuse anything for Guava you might find useful.

gissuebot commented 9 years ago

Original comment posted by neveue on 2011-12-22 at 11:13 PM


Semi off-topic, but I'd use bcrypt instead of salted / stretched SHA-256 for password hashing:

http://codahale.com/how-to-safely-store-a-password/

It's more secure, and it's also simpler to use, since it handles salting / stretching for you.

There is a java implementation at

http://code.google.com/p/jbcrypt/

bcrypt stores the salt and hash as a String.

gissuebot commented 9 years ago

Original comment posted by toellrich on 2011-12-23 at 03:02 AM


bcrypt looks like a great library. It's "only" version 0.3, though, which might be a dealbreaker for the guys at my company who are in charge of deciding about using a 3rd party library like that. It was tough getting them to allow Guava.

gissuebot commented 9 years ago

Original comment posted by neveue on 2011-12-23 at 06:46 AM


The java implementation (jBCrypt) is indeed in version 0.3, and I guess that might be a problem to get it accepted as a 3d party library...

bcrypt itself is 12 years old, though, and the java implementation is only one of many implementations. I think the version 0.3 thing is just a version naming scheme problem, since the Java implementation is quite old (version 0.1 was released in May 2006, 0.2 in April 2008, and 0.3 in February 2010).

http://en.wikipedia.org/wiki/Bcrypt

http://www.mindrot.org/projects/jBCrypt/

gissuebot commented 9 years ago

Original comment posted by toellrich on 2011-12-23 at 01:00 PM


Yeah, sorry, that's what I meant: jbcrypt. I also wanted to add that the passwords I want to hash are for users that are all employees of our company and they are for an application that drives our business, but which is not accessible from the outside. I'm just looking for a simple, but fairly secure encoding that is better than storing the passwords as plain texts (which is how they are stored at the moment!). A hacker wouldn't really have much to gain by cracking the passwords, except for disrupting our business processes (which might be all they want to do).

Nevertheless, using a 3rd party library at version 0.3 might not be justifiable in this case.

After reading the blog by Coda Hale, I've updated the above code to hide the salt inside the hash at an offset based on the password's length. A hacker should not be able to discern what the salt is which should make cracking the encoding all the more difficult:

http://pastebin.com/t2PwAZHY

gissuebot commented 9 years ago

Original comment posted by wasserman.louis on 2011-12-24 at 04:15 PM


I wonder how difficult it would be to take a given HashFunction and iterate it n times. That'd be my preferred way to address this issue.

gissuebot commented 9 years ago

Original comment posted by wasserman.louis on 2012-01-05 at 08:53 PM


(No comment entered for this change.)


Labels: Type-Enhancement, Package-Hash

gissuebot commented 9 years ago

Original comment posted by kevinb@google.com on 2012-01-10 at 11:53 PM


It doesn't seem clear that Guava needs to add anything. I think a user could pretty easily create a HashFunction implementation that delegates to another HashFunction and feeds the result through itself N times; if not, please let us know.


Status: WontFix

scottbessler commented 9 years ago

an example at least showing how to create that custom hashfunction would be great.

kluever commented 9 years ago

"It's easy to get carried away and try to combine different hash functions, hoping that the result will be more secure. In practice, though, there is very little benefit to doing it" via https://crackstation.net/hashing-security.htm

To Store a Password

  1. Generate a long random salt using a CSPRNG (for Java, they recommend SecureRandom).
  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.

So I think you've overcomplicating the problem. Just use SecureRandom and Hashing.sha256().

kevinb9n commented 9 years ago

I think the most relevant part of that page is this:

Don't try to invent your own–simply iteratively hashing the hash of the password isn't enough as it can be parallelized in hardware and executed as fast as a normal hash. Use a standard algorithm like PBKDF2 http://en.wikipedia.org/wiki/PBKDF2 or bcrypt http://en.wikipedia.org/wiki/Bcrypt.

On Tue, Feb 17, 2015 at 8:46 AM, Kurt Alfred Kluever < notifications@github.com> wrote:

"It's easy to get carried away and try to combine different hash functions, hoping that the result will be more secure. In practice, though, there is very little benefit to doing it" via https://crackstation.net/hashing-security.htm

To Store a Password

  1. Generate a long random salt using a CSPRNG (for Java, they recommend SecureRandom).
  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.

So I think you've overcomplicating the problem. Just use SecureRandom and Hashing.sha256().

— Reply to this email directly or view it on GitHub https://github.com/google/guava/issues/831#issuecomment-74701416.

Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb@google.com