如何在 javascript 中复制 symfony passwordEncode

How to duplicate symfony passwordEncode in javascript

我需要创建一个与 Symfony 3 encodePassword 相同的 javascript 散列算法。

这与 symfony3 中的问题类似: Symfony2 password encoder function in Javascript

这是创建一个消息摘要以在 Symfony 中使用 wsse headers 和在 postman 中使用 fosbundle 测试休息端点。

我已经设法简化并复制了 PHP

中的 Symfony 哈希函数
$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==

但尝试使用 CryptoJS 在 javascript 中复制它被证明很麻烦。我怀疑它也与字符编码有关。

根据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.


<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre><code>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>

我尝试了很多不同的方法来首先转换为单词数组等等,但是 none 似乎想出了相同的散列

https://jsfiddle.net/munkiepus/awdoq4kL/34/

编辑:我认为问题在于 php 使用某种形式的原始二进制文件

$digest = hash("sha512", $salted, true);的结果输出到终端显示:

▒q▒$▒b▒x]▒▒j▒▒=s1▒▒� ▒▒▒▒▒%g<▒##▒ٛ▒▒|z▒n▒▒▒ FcG.:▒▒os▒▒▒C

所以也许它毕竟不是 JS 中的 possible。如果摘要在每次迭代期间都被编码为可读字符串,那么它可能是 possible,如链接示例中所示。

你为什么需要那个?最好的事情是你只在一侧加密它,无论是从 JS 还是 Symfony 并且只比较哈希值。

另一种选择是不使用 encodePassword(),例如使用 md5()

在此 link 向您展示其工作原理 encodePassword()

此致!

好的,这是二进制数据导致的问题,如果我们将单词数组转换为二进制字符串,它就可以工作。

需要一些其他函数来进行转换,请参阅函数的可运行示例。例子


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>