Как продублировать Symfony PasswordEncode в JavaScript - PullRequest
0 голосов
/ 16 апреля 2019

Мне нужно создать алгоритм хэширования javascript, такой же, как Symfony 3 encodePassword.

Это было похоже на проблему, но в symfony3: Функция кодировки пароля Symfony2 в Javascript

это создать дайджест сообщения для проверки конечной точки отдыха с заголовками wsse в Symfony и fosbundle в почтальоне.

Мне удалось упростить и дублировать хеширующую функцию Symfony в 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==

но попытка воспроизвести его в javascript с помощью CryptoJS оказывается проблематичной. Я подозреваю, что это связано и с кодировкой символов.

в соответствии с https://code.google.com/archive/p/crypto-js/#The_Hasher_Input

Алгоритмы хеширования принимают либо строки, либо экземпляры CryptoJS.lib.WordArray [...] массив 32-битных слов. Когда вы передаете строка, она автоматически преобразуется в WordArray, закодированный как UTF-8.


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

Я пробовал много разных способов сначала преобразовать в массив слов и т. Д., Но, похоже, ни один из них не дал такой же хэш

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

РЕДАКТИРОВАТЬ: я думаю, что проблема в том, что PHP использует некоторую форму необработанных двоичных файлов

вывод результата $digest = hash("sha512", $salted, true); на терминал показывает:

▒q▒ $ ▒b▒x] ▒▒j▒▒ = s1▒▒ ▒▒▒▒▒% г <▒ ## ▒ ▒▒ | z▒n▒▒▒ FcG.:▒▒os▒▒▒C</p>

так что, возможно, это не возможно в JS в конце концов. если дайджест был закодирован в читаемую строку во время каждой итерации, то это возможно, как в связанном примере.

Ответы [ 2 ]

0 голосов
/ 17 апреля 2019

Хорошо, проблема возникла из-за двоичных данных, если мы преобразовали массив слов в двоичную строку, то это работает.

требовались некоторые другие функции для выполнения преобразований, см. Пример запуска функций. Пример


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>
0 голосов
/ 16 апреля 2019

Зачем тебе это? Лучше всего то, что вы шифруете его только на одной стороне, от JS или Symfony, и сравниваете только хэши.

Другой вариант - не использовать encodePassword() и использовать md5(), например.

В этой ссылке показано, как это работает encodePassword().

Привет!

...