I need to create a javascript hashing algorithm the same as Symfony 3 encodePassword.
This was a similar problem to that in but in symfony3: Symfony2 password encoder function in Javascript
this is to create a message digest to test a rest endpoint with wsse headers in Symfony with fosbundle in postman.
I've managed to simplify and duplicate the Symfony hashing function in PHP
$pass = "hello";
$salt = "";
$iterations=5000;
echo $this->encoder->encodePassword($pass,$salt);
//contains: U5xyFq7KQU1CWeX3UcLB0mwWZZQUq0PL8U+GLWomfGW/WQWxxGLi+0ifhmnlw/gQ5pPjNNZV1/q8kMVpAXsFZw==
//simplyfying and replicating the hashing algo in php with same pass/salt:
$salted = $pass.$salt;
$digest = hash("sha512", $salted, true);
for($i=1; $i<$iterations; $i++) {
$digest = hash("sha512", $digest.$salted, true);
}
echo base64_encode($digest);
//contains: U5xyFq7KQU1CWeX3UcLB0mwWZZQUq0PL8U+GLWomfGW/WQWxxGLi+0ifhmnlw/gQ5pPjNNZV1/q8kMVpAXsFZw==
but trying to replicate it in javascript using CryptoJS is proving troublesome. I suspect its to do with the character encoding too.
according to https://code.google.com/archive/p/crypto-js/#The_Hasher_Input
The hash algorithms accept either strings or instances of CryptoJS.lib.WordArray [...] an array of 32-bit words. When you pass a string, it's automatically converted to a WordArray encoded as UTF-8.
password = 'hello';
//attempt 1 use hex converted pass
hexpass = CryptoJS.enc.Utf8.parse(password);
digest = CryptoJS.SHA512(hexpass);
for (i = 1; i < 5000; ++i) {
hexvar = CryptoJS.SHA512(digest + hexpass);
}
digest = digest.toString(CryptoJS.enc.Base64);
console.log(digest);
// need hash to contain: U5xyFq7KQU1CWeX3UcLB0mwWZZQUq0PL8U+GLWomfGW/WQWxxGLi+0ifhmnlw/gQ5pPjNNZV1/q8kMVpAXsFZw==
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
I've tried many different ways to with converting to word array first etc. but none seem to come up with the same hash
https://jsfiddle.net/munkiepus/awdoq4kL/34/
EDIT: i think the problem is that the php uses some form of raw binary
outputting the result of $digest = hash("sha512", $salted, true);
to the terminal shows:
▒q▒$▒b▒x]▒▒j▒▒=s1▒▒� ▒▒▒▒▒%g<▒##▒ٛ▒▒|z▒n▒▒▒ FcG.:▒▒os▒▒▒C
so maybe it's not possible in JS after all. if the digest was encoded to a readable string during each iteration then it may be possible, as in the linked example.
Ok so it was the binary data causing the problem, if we convert the word array into a binary string it works.
needed some other functions to do the conversions see the runnable example for the functions. example
hashWordArray = CryptoJS.SHA512(password);
uint8array = convertWordArrayToUint8Array(hashWordArray);
binaryString = convertUint8ArrayToBinaryString(uint8array);
for (var i=1; i<5000; i++) {
wordArrayFromString = CryptoJS.enc.Latin1.parse(binaryString+password);
hashWordArray = CryptoJS.SHA512(wordArrayFromString);
uint8array = convertWordArrayToUint8Array(hashWordArray);
binaryString = convertUint8ArrayToBinaryString(uint8array);
}
b64_encoded = btoa(binaryString);
const password = "hello";
// set up the container to display output
var div = document.getElementById('message');
div.innerHTML += 'string to hash:<br>';
div.innerHTML += password+'<br><br>';
div.innerHTML += 'php generated hash:<br>';
correct_hash = 'U5xyFq7KQU1CWeX3UcLB0mwWZZQUq0PL8U+GLWomfGW/WQWxxGLi+0ifhmnlw/gQ5pPjNNZV1/q8kMVpAXsFZw=='
div.innerHTML += correct_hash+'<br><br>';
//actually do the hashing
hashWordArray = CryptoJS.SHA512(password);
uint8array = convertWordArrayToUint8Array(hashWordArray);
binaryString = convertUint8ArrayToBinaryString(uint8array);
for (var i=1; i<5000; i++) {
wordArrayFromString = CryptoJS.enc.Latin1.parse(binaryString+password);
hashWordArray = CryptoJS.SHA512(wordArrayFromString);
uint8array = convertWordArrayToUint8Array(hashWordArray);
binaryString = convertUint8ArrayToBinaryString(uint8array);
}
b64_encoded = btoa(binaryString);
// add the outputr to the display container
div.innerHTML += 'javascript generated hash:<br>';
div.innerHTML += b64_encoded +"<br><br>"; //b64_encode()
// functions from
// https://gist.github.com/getify/7325764
function convertWordArrayToUint8Array(wordArray) {
var len = wordArray.words.length,
u8_array = new Uint8Array(len << 2),
offset = 0, word, i
;
for (i=0; i<len; i++) {
word = wordArray.words[i];
u8_array[offset++] = word >> 24;
u8_array[offset++] = (word >> 16) & 0xff;
u8_array[offset++] = (word >> 8) & 0xff;
u8_array[offset++] = word & 0xff;
}
return u8_array;
}
function convertUint8ArrayToBinaryString(u8Array) {
var i, len = u8Array.length, b_str = "";
for (i=0; i<len; i++) {
b_str += String.fromCharCode(u8Array[i]);
}
return b_str;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<div id="message"></div>