Foros de discusión

Replicate PBKDF2PasswordEncryptor in PHP

Gabrijel Gavranovic, modificado hace 6 años.

Replicate PBKDF2PasswordEncryptor in PHP

New Member Mensaje: 1 Fecha de incorporación: 10/05/17 Mensajes recientes
For a project we need to be able to mimic the password generation in a PHP app so we can validate the password hash directly against the DB without going through Liferay.
My Java knowledge and my Liferay knowledge isn't as splendid as I'd like it to be... any help would be greatly apreciated!

The Liferay version that's active is v 6.2 and the used password/hash method is PBKDF2PasswordEncryptor, keysize: 160, rounds: 128000.

If managed to extract the keysize and the rounds form the hash:
$rawEncrypted = base64_decode($encrypted);
// keysize is found in the first 4 bytes
$keySize = unpack('N', substr($raw, 0, 4));
$keySize = end($keySize); // result: 160
// rounds is found in the next 4 bytes
$rounds  = unpack('N', substr($raw, 4, 4)); // result: 128000
$rounds  = end($rounds);


Now, when I'm trying to get the salt (next 8 bytes) I'm not quote sure if I'm getting the right salt, two examples:
$salt = unpack('N', substr($raw, 8, 8)); // returns a large integer, e.g. 4006721064

$salt = unpack('H*', substr($raw, 8, 8)); // return a string/hex, e.g. eedf4e8ed639571a


Now, the next part gets me quite confused. There are only 36 chars stored in the DB for the password hash. So that leaves (36-4-4-8=) 20 bytes/chars left for the password hash (from plain text).
Am I missing something? I thought I'd have to use the PHP function "hash_pbkdf2" (with the exact same specs: sha1, plain pass, found salt, rounds, keysize) and I end up with a large hash/string. So now:
  • Am I generating the pass correctly (do I need to do something with the salt?)
  • How am I supposed to create the final hash (36 chars) with the keysize, rounds and salt embedded?


Thank you very much,
GG.
thumbnail
David H Nebinger, modificado hace 6 años.

RE: Replicate PBKDF2PasswordEncryptor in PHP

Liferay Legend Mensajes: 14919 Fecha de incorporación: 2/09/06 Mensajes recientes
Seems like an awful PITA if you ask me.

Why not just invoke an authenticated web service call against Liferay w/ the credentials in a BasicAuth header and evaluate the response code from the server (200 vs 40x codes)?








Come meet me at the 2017 LSNA!
thumbnail
Tomas Polesovsky, modificado hace 6 años.

RE: Replicate PBKDF2PasswordEncryptor in PHP

Liferay Master Mensajes: 676 Fecha de incorporación: 13/02/09 Mensajes recientes
For any future readers

PBKDF2PasswordEncryptor.java#L79-L87

So the password is saved as [key size in 4 bytes] [rounds in 4 bytes] [salt in 8 bytes] [secret key, length based on key size]

Example
MariaDB [lportal_trunk]> select password_ from User_ where emailAddress = 'test@liferay.com';
+--------------------------------------------------+
| password_                                        |
+--------------------------------------------------+
| AAAAoAAB9AC8xZlFnkixAsLnhJKYm56jV4o/6fpg84YfmlFE |
+--------------------------------------------------+


Translated into hex:

echo -n 'AAAAoAAB9AC8xZlFnkixAsLnhJKYm56jV4o/6fpg84YfmlFE' | base64 -d - | xxd
0000000: 0000 00a0 0001 f400 bcc5 9945 9e48 b102  ...........E.H..
0000010: c2e7 8492 989b 9ea3 578a 3fe9 fa60 f386  ........W.?..`..
0000020: 1f9a 5144                                ..QD


So applied: [0000 00a0] [0001 f400] [bcc5 9945 9e48 b102] [c2e7 8492 989b 9ea3 578a 3fe9 fa60 f386 1f9a 5144]

int keySize = 0x0000 00a0 = 160 (20 bytes)
int rounds = 0x000 1f400 = 128000
byte[] salt = [0xbc, 0xc5, 0x99, 0x45, 0x9e, 0x48, 0xb1, 0x02]
byte[] pbkdf2Hash = [0xc2, 0xe7, 0x84, 0x92, 0x98, 0x9b, 0x9e, 0xa3, 0x57, 0x8a, 0x3f, 0xe9, 0xfa, 0x60, 0xf3, 0x86, 0x1f, 0x9a, 0x51, 0x44]


Testing with PHP:
(cat <<"EOF"
<!--?php
$keySize = 20;
$rounds = 128000;
$salt = implode(array_map("chr",[0xbc, 0xc5, 0x99, 0x45, 0x9e, 0x48, 0xb1, 0x02]));
$expected = bin2hex(implode(array_map("chr",[0xc2, 0xe7, 0x84, 0x92, 0x98, 0x9b, 0x9e, 0xa3, 0x57, 0x8a, 0x3f, 0xe9, 0xfa, 0x60, 0xf3, 0x86, 0x1f, 0x9a, 0x51, 0x44])));

$password = "test";
$hash = bin2hex(hash_pbkdf2("sha1", $password, $salt, $rounds, $keySize, true));

echo "
Expected: $expected
Actual:   $hash";

EOF
) | php</code-->
<br><pre><code>Expected: c2e78492989b9ea3578a3fe9fa60f3861f9a5144 Actual: c2e78492989b9ea3578a3fe9fa60f3861f9a5144</code></pre>