5

I'm using Play 1.2.1. I want to hash my users password. I thought that Crypto.passwordHash will be good, but it isn't. passwordHash documentation says it returns MD5 password hash. I created some user accounts in fixture, where I put md5 password hash:

  ...
User(admin):
  login: admin
  password: f1682b54de57d202ba947a0af26399fd
  fullName: Administrator
  ...

The problem is, when I try to log in, with something like this:

user.password.equals(Crypto.passwordHash(password))

and it doesn't work. So I put a log statement in my autentify method:

Logger.info("\nUser hashed password is %s " +
                    "\nPassed password is %s " +
                    "\nHashed passed password is %s",
                    user.password, password, Crypto.passwordHash(password));

And the password hashes are indeed different, but hey! The output of passwordHash method isn't even an MD5 hash:

15:02:16,164 INFO  ~
User hashed password is f1682b54de57d202ba947a0af26399fd
Passed password is <you don't have to know this :P>
Hashed passed password is 8WgrVN5X0gK6lHoK8mOZ/Q==

How about that? How to fix it? Or maybe I have to implement my own solution?

jjczopek
  • 3,319
  • 2
  • 32
  • 72
  • BTW it's not very clever to use simple MD5-Hash for passwords. There should be at least a salt in addition. – niels Jun 09 '11 at 18:20
  • @niels - I know that, but this is just a simple sample project for learning play! – jjczopek Jun 09 '11 at 18:22
  • I think you might like the answer in below link, it suggests how to use md5 in java http://stackoverflow.com/questions/415953/generate-md5-hash-in-java – engin Jun 08 '11 at 13:43

3 Answers3

5

Crypto.passwordHash returns base64-encoded password hash, while you are comparing to hex-encoded.

Nickolay Olshevsky
  • 13,706
  • 1
  • 34
  • 48
3

MD5 outputs a sequence of 16 bytes, each byte having (potentially) any value between 0 and 255 (inclusive). When you want to print the value, you need to convert the bytes to a sequence of "printable characters". There are several possible conventions, the two main being hexadecimal and Base64.

In hexadecimal notation, each byte value is represented as two "hexadecimal digits": such a digit is either a decimal digit ('0' to '9') or a letter (from 'a' to 'f', case is irrelevant). The 16 bytes thus become 32 characters.

In Base64 encoding, each group of three successive bytes is encoded as four characters, taken in a list of 64 possible characters (digits, lowercase letters, uppercase letters, '+' and '/'). One or two final '=' signs may be added so that the encoded string consists in a number of characters which is multiple of 4.

Here, '8WgrVN5X0gK6lHoK8mOZ/Q==' is the Base64 encoding of a sequence of 16 bytes, the first one having value 241, the second one 104, then 43, and so on. In hexadecimal notation, the first byte would be represented by 'f1', the second by '68', the third by '2b'... and the hexadecimal notation of the complete sequence of 16 bytes is then 'f1682b54de57d202ba947a0af26399fd', the value that you expected.

The play.libs.Codec class contains methods for decoding and encoding Base64 and hexadecimal notations. It also contains Codec.hexMD5() which performs MD5 hashing and returns the value in hexadecimal notation instead of Base64.

Thomas Pornin
  • 72,986
  • 14
  • 147
  • 189
2

as Nickolay said you are comparing Hex vs Base-64 strings. Also, I would recommend using BCrypt for that, not the Crypto tool of Play.

Pere Villega
  • 16,429
  • 5
  • 63
  • 100