Yes, but won't prevent a brute force attack. A single standard hash is not secure even with salting.
--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
Here is some code that:
- hashes each password with a secret from application.conf, you can
change this secret to invalidate all passwords, also to crack
passwords you need both this secret (from disk) and the salt (from
database)
- the SHA512 hash is then bcrypt'd with a salt
It uses http://www.mindrot.org/projects/jBCrypt/ (afaik you just have
to cut-and-paste the BCrypt.java file, it doesn't seem to be
Maven-published)
Havoc
/**
* Copyright (C) 2011 Havoc Pennington
* Licensed under the Apache License, Version 2.0
*/
package security
import java.util.UUID
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import org.apache.commons.codec.binary.Hex
import org.apache.commons.codec.digest.DigestUtils
import bcrypt.BCrypt;
object Algorithms {
// HMAC SHA-512 hash
private def signature(message: String, key: String): String = {
require(key.length > 0)
val mac = Mac.getInstance("HmacSHA512");
val signingKey = new SecretKeySpec(key.getBytes("utf-8"), "HmacSHA512");
mac.init(signingKey);
val messageBytes = message.getBytes("utf-8");
val resultBytes = mac.doFinal(messageBytes);
new String(Hex.encodeHex(resultBytes))
}
def hashPassword(password: String, serverWidePasswordSecret: String) = {
if (password.length == 0)
throw new IllegalArgumentException("Password may not be zero-length")
// we add the server's secret key to the password,
// the idea is to require stealing both the server
// key and the database, which might raise the bar
// a bit.
val intermediate = signature(password, serverWidePasswordSecret)
BCrypt.hashpw(intermediate, BCrypt.gensalt())
}
def checkPassword(password: String, passwordHash: String,
serverWidePasswordSecret: String) = {
val intermediate = signature(password, serverWidePasswordSecret)
BCrypt.checkpw(intermediate, passwordHash)
}
}
}
}
--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
* "The nonce for the hmac value is designed to be stored on the file
system and not in the databases storing the password hashes. In the
event of a compromise of hash values due to SQL injection, the nonce
will still be an unknown value since it would not be compromised from
the file system. This significantly increases the complexity of brute
forcing the compromised hashes considering both bcrypt and a large
unknown nonce value"
* "The hmac operation is simply used as a secondary defense in the
event there is a design weakness with bcrypt that could leak
information about the password or aid an attacker"
I guess they use 512 because why not use the maximally-strong SHA
flavor (this is the rare case where having an algorithm be slow is
desirable, so you can use the slowest-but-strongest SHA).
Imagine you're using a database-as-a-service provider or something
like that, and the db provider is hacked, but your app server is not -
the extra secret hashed in from application.conf could save you in
that case and make it impossible to search for "123password" and
"letmein" and all those other common crappy passwords. Without the
extra secret, people can still search for them... even though bcrypt
is slow and the salt requires recomputing the hash for every
user-password combo, some of the common passwords are common enough
they'd likely get one eventually.
Havoc
The thing to note is that, even when using BCrypt, you need generate a brand new salt for each password. The salt can be anything random and the salt doesn't need to be protected. So you can store your password in a "salt : hash" format where the first part is the plaintext salt. The salt has no use to attackers, it's only used to ensure that the hashes are not predictable and the attacker cannot infer relationships between the hashes. It's pretty much the same idea as IVs (Initialization Vectors) [1] in encryption.
HTH,
Drew
[1] http://en.wikipedia.org/wiki/Initialization_vector
Are you sure that you need to actually store a salt value? I was under
the impression that BCrypt stored it implicitly and there is no
documentation of such a requirement in the jbcrypt documentation. From
a quick test:
$ scala -classpath lib/jbcrypt-0.3m.jar
Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM,
Java 1.6.0_29).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import org.mindrot.jbcrypt._
import org.mindrot.jbcrypt._
scala> BCrypt.hashpw("hello", BCrypt.gensalt())
res0: java.lang.String =
$2a$10$76eXtd9ab8sbZWLlGxCmfOVr2ENud6JFOTyp3L9sJokSZwROChIgy
scala> BCrypt.hashpw("hello", BCrypt.gensalt())
res1: java.lang.String =
$2a$10$F5g.8C3b.3sBBm.LCbCbw.N/2QvHNTwJDCX4aCgRNz0UL.lqv/CpO
scala> BCrypt.checkpw("hello", res0)
res2: Boolean = true
scala> BCrypt.checkpw("hello", res1)
res3: Boolean = true
scala> BCrypt.checkpw("hello!", res1)
res4: Boolean = false
-- Drew
New play webdev here.I am trying to implement an encryption method for user data that is to be stored in a database (mysql). I'm following the examples listed in this discussion, however, the Crypto class in play 2.0.4 does not include the passwordHash method any longer. I found the old Crypto java source (https://github.com/playframework/play/blob/master/framework/src/play/libs/Crypto.java), however, since the method has been removed I am now wondering if something new has come up with regards to the Play Framework and should be used instead.Does anybody know why the method has been removed?On Wednesday, July 25, 2012 10:02:18 AM UTC+2, Gijsbert Peijs wrote:Hi Ron,The dependency works like a charm and also your code example is really helpful but there is one thing that breaks the example: The order of hashing.jBCrypt stores it's randomly generated salts in the password hash which is a really great idea because it allows BCrypt.checkpw to work without you providing the salt. But if you hash the BCrypt password with SHA512, there is no way to determine the salt again so BCrypt.checkpw won't work. By first applying the SHA512 hash, you can encrypt the hashed password with BCrypt with a random salt. Now all you have to do is SHA512-hash the plain text password the user provides and use BCrypt.checkpw to validate against the password stored in the database.In code this looks something like:
/*
* hash passwords. First SHA512 using Play's internal Crypto and subsequently BCrypt (with random Salt).
*/
public static String hashPassword(String password) {
String salt = BCrypt.gensalt();
return BCrypt.hashpw(Crypto.passwordHash(password, Crypto.HashType.SHA512), salt);
}
/*
* encrypts the provided plain text password to SHA512 and then uses BCrypt to validate against the stored double encrypted password.
*/
public static boolean matchPasswords(String providedPassword, String storedPassword) {
String sha512Password = Crypto.passwordHash(providedPassword, Crypto.HashType.SHA512); // Only SHA512, no BCrypt
return BCrypt.checkpw(sha512Password, storedPassword);
}Hope this is of any use.Regards,Gijs.
Op donderdag 2 februari 2012 18:43:01 UTC+1 schreef Ron Gross het volgende: