Edit: my question has been updated, check the bottom of this post for the latest issue. I left the rest up for people who want to read the whole story :)
I've been working on translating a small Java application into Node.js, which for the most part has been going very well. I've had to look up a lot of Java functions to figure out what they do and how to replicate their behaviour in Node (since I have pretty much no experience whatsoever with Java), but I got most of the functionality working by now.
Unfortunately there is one bit that I just can't seem to get working. It is a method used to generate a password hash, using a set of high level Java-specific functions that don't seem to exist in Node. I've been trying for two days to get this working but I just can't get the results I want.
This is the original Java code:
public static String hashPassword(final String password, final String salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
final char[] passwordChars = password.toCharArray();
final byte[] saltBytes = salt.getBytes();
final PBEKeySpec spec = new PBEKeySpec(passwordChars, saltBytes, 1000, 192);
final SecretKeyFactory key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
final byte[] hashedPassword = key.generateSecret(spec).getEncoded();
return String.format("%x", new BigInteger(hashedPassword));
}
Note: the salt is a fixed value, it is not random. I know this is not how it should be, but this is how the application is set up. So, since the Java code always gets the same result, it should be possible to get the same result in Node as well.
I've tried using crypto.pbkdf2
, using various ciphers that seemed similar, but it all gave me a different outcome than the Java code. So I figured I'd ask here, to see if anyone knows how to do this, or has any suggestions on how to approach this.
Note that (as I said) I don't know a thing about Java, so my difficulties getting this to work probably come from the fact that I have a hard time grasping just what is happening within this method, and googling the various functions used gives conflicting answers and mostly just shows other people having a hard time with them as well.
So there are actually three questions I'm asking:
- Is this possible to replicate in Node.js or does Java use functionality that just doesn't exist within Node?
- Could someone who has more Java experience explain the various lines in this code, and what each one does? Preferably in a way that someone with a decent level of Node.js experience (and some PHP) but who never worked with Java would understand :)
- If anyone knows, which Node functions am I looking at to get this working? Can I do it with the built-in crypto module or will I need additional modules?
Lastly, before you say "just implement a Node-specific hashing algorithm" (which would be the easier option), I can't do that since this is to be used on existing databases that already contain these hashed passwords and that are used by other existing Java applications as well. Changing the other applications or the database is currently not an option.
UPDATE: I've gotten an answer that was very helpful, and now I got this in my Node.js code:
hashPassword = function(password, salt){
crypto.pbkdf2(password, new Buffer(salt), 1000, 24, 'sha1', function(err, key){
}
}
That's where I'm stuck again. I can't get the string value I need from the key. I googled a bit and found out that the String.format
line in the Java code turns the BigInteger into a hexadecimal integer, but I can't seem to get the correct value.
- I tried simply
key.toString('hex')
but that didn't work. - I found this node-biginteger module, and tried
BigInteger.fromBuffer(1, key).toString(24)
and some variations thereupon, but it still gives me a very different outcome than the Java application.
Any help on how to get the correct string value from the buffer would be very much appreciated.
Update2: I finally got my application working, as it turns out it was an external module that outputted bad hashes. Implementing the crypto module properly fixed it.