Javascript不匹配中的PHP Pack/Unpack实现 [英] PHP Pack/Unpack implementation in Javascript Mismatch

查看:114
本文介绍了Javascript不匹配中的PHP Pack/Unpack实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据此问题的相关答案,我尝试输入类似于PHP流程的打包/解包解决方案,但是在Nodejs(Javascript)中使用 md5 缓冲包

As per this question's related answer, I'm attempting to put together a pack/unpack solution resembling this PHP process, however in Nodejs (Javascript) using md5 and bufferpack

这是PHP方法(改编自 DaloRADIUS :

Here's the PHP approach (adapted from DaloRADIUS:

  $challenge = 'c731395aca5dcf45446c0ae83db5319e';
  $uamsecret = 'secret';
  $password = 'password';

  $hexchal = pack ("H32", $challenge);
  $newchal = pack ("H*", md5($hexchal . $uamsecret));
  $response = md5("\0" . $password . $newchal);
  $newpwd = pack("a32", $password);
  $pappassword = implode ("", unpack("H32", ($newpwd ^ $newchal)));

  echo "Response: ---> ", $response, "\n";
  echo "New Password: ---> ", $newpwd, "\n";
  echo "Pap Password: ---> ", $pappassword, "\n";

以上内容与之相呼应:

以上为纯文本:

Response: ---> 2d4bd27184f5eb032641137f728c6043
New Password: ---> password
Pap Password: ---> 356a1fb08f909fc400dfe448fc483ce3

在Javascript中,这是我现在正在做的事情:

In Javascript, here's what I'm doing now:

  var challenge = 'c731395aca5dcf45446c0ae83db5319e';
  var uamsecret = 'secret';
  var password = 'password';

  var hexchal = pack.pack("H32", challenge);
  var newchal = pack.pack("H*", md5(hexchal + uamsecret));
  var response = md5("\0" + password + newchal);
  var newpwd = pack.pack("a32", password);
  var pappassword = pack.unpack("H32", (newpwd ^ newchal)).join("");

  console.log("Response: --> ", response);
  console.log("New Password: -->", newpwd);
  console.log("Pap Password: --->", pappassword);

哪个给出结果:

在JSON中:

以纯文本格式:

Response: -->  e8a54a55cbcd81dbc2bdfd9b197d62af
New Password: --> <Buffer >
Pap Password: ---> NaN

以上所有代码段均位于此处: RadiusNES

All the above snippets are available here: RadiusNES

我对整个过程的理解不是最好的,并且会欣赏见识和我要去哪里的地方.

My understanding in this whole process isn't the best, and will appreciate insights and where I'm going wrong.

为什么不匹配?

推荐答案

由于 Javascript bufferpack模块返回数组.同样,您不能在Javascript中对字符串进行异或运算.

The translation does not work because the PHP Pack function uses different format strings and returns strings, whilst the Javascript bufferpack module returns arrays. Also you cannot xor strings in Javascript.

虽然可能有一些模块可以做您想做的事情,但我有自己的函数来解析十六进制字符串.我也喜欢修改并非所有人都同意的原型,但是可以将其转换为常规函数.

Whilst there may be modules to do what you want, I have my own functions for parsing hex strings. Also I like modifying prototypes which not everyone agrees with, but these could be converted to regular functions.

String.prototype.pad = function( length ,padding ) {

    var padding = typeof padding === 'string' && padding.length > 0 ? padding[0] : '\x00'
        ,length = isNaN( length ) ? 0 : ~~length;

    return this.length < length ? this + Array( length - this.length + 1 ).join( padding ) : this;

}

String.prototype.packHex = function() {

    var source = this.length % 2 ? this + '0' : this
        ,result = '';

    for( var i = 0; i < source.length; i = i + 2 ) {
        result += String.fromCharCode( parseInt( source.substr( i , 2 ) ,16 ) );
    }

    return result;

}

var challenge = 'c731395aca5dcf45446c0ae83db5319e'
    ,uamsecret = 'secret'
    ,password = 'password';

var hexchal = challenge.packHex();
var newchal = md5( hexchal + uamsecret ).packHex();
var response = md5( '\0' + password + newchal );
var newpwd = password.pad( 32 );
var pappassword = '';
for( var i = 0; i < newchal.length; i++ ) {
    pappassword += ( newpwd.charCodeAt( i ) ^ newchal.charCodeAt( i ) ).toString( 16 );
}

console.log("Response: --> ", response);
console.log("New Password: -->", newpwd);
console.log("Pap Password: --->", pappassword);

在String原型中定义了两个函数来代替pack函数的使用:

Two functions are defined in the String prototype to replace the use of the pack function:

.pad( 32, string )用于填充带空值的字符串,以提供与pack( 'a32', string )相同的结果.尽管这里不需要,但如果要用非空字符填充字符串,它也需要第二个参数.

.pad( 32, string ) is used to pad out a string with nulls to give the same results as pack( 'a32', string ). Although not needed here it also takes a second parameter if wanting to pad the string ith a character other than nulls.

.packHex等效于pack( 'H*' ,string ),并将每对十六进制字符的代码转换为一个字符.理想情况下,该函数需要更多验证以测试字符串是否为有效的十六进制.

.packHex is the equivalent of pack( 'H*' ,string ) and translating the code of each pair of hex characters into a character. The function ideally needs more validation to test the string is a valid hex one if is to be used.

在定义了输入之后,接下来的四行使用这些函数而不是pack来设置变量.

After the inputs have been defined, the next four lines instead set variables using these functions rather than pack.

由于Javascript本身无法对字符串进行异或运算,因此您需要使用循环来提取每个字符,将其转换为数字,然后对这些值进行异或运算,然后将结果转换回字符以创建pappassword字符串.

Because Javascript cannot natively xor strings, you then need to use a loop to extract each character, convert it to a numeric, xor those values, then convert the result back into a character to create the pappassword string.

对我来说,这将会返回

Response: -->  – "fbfd42ffde05fcf8dbdd02b7e8ae2d90"
New Password: --> – "password������������������������"
Pap Password: ---> – "dcbdacb03f5d38ca33c128b931c272a"

这是结果,但不幸的是,它与PHP代码有所不同.

Which is a result, but unfortunately a different on from the PHP code.

这是因为我的PHP安装被配置为内部使用ISO-8859-1编码,而Javascript本身使用UTF-16.

This is because my installation of PHP is configured to use ISO-8859-1 encoding internally, whilst Javascript natively uses UTF-16.

这在正常使用中不是问题,但这意味着相应的md5函数将看到不同的值,因此返回不同的哈希值.

This is not a problem in normal use, but it means the respective md5 functions will be seeing different values and therefore return a different hash.

假设您正在使用PHP后端编写身份验证例程,那么您显然需要一致的结果.可能有一些模块可以转换Javscript值的编码以实现兼容性,但是对PHP代码进行更改要容易得多.

因为我们知道十六进制字符串将是一个字节,所以Javascript有效地使用了UTF-8,因此PHP可以通过使用utf8_encode()函数在对md5打包之前对已打包的十六进制字符串进行转换来做到这一点.

Because we know the hex strings will be one byte, Javascript is effectively using UTF-8, so PHP can do the same by using the utf8_encode() function to convert the packed hex strings before md5ing them.

最初,我认为Javascript会因此在内部将已编码的十六进制字符转换为它们的unicode等效项,但事实并非如此.相反,是Javascript中使用的md5模块对输入执行UTF-8转换.

Originally I thought that Javascript was internally converting the encoded hex characters into their unicode equivalents because of this, but this was not the case. Instead it was the md5 module being used in Javascript that was performing a UTF-8 conversion on the input.

这留下了两个可能的选择.

This leaves two possible options.


1.使用UTF-8 PHP

如果可能的话,您可以重新配置PHP服务器以使用UTF-8编码.或者,您可以更改脚本以使用utf8_encode()函数来反映与Javascript中相同的过程,并在将十六进制打包的字符串传递给md5()

If possible you can reconfigure your PHP server to use UTF-8 encoding. Or you can change your script to use the utf8_encode() function to mirror the same process as is happening in the Javascript, and convert the hex packed strings to UTF-8 before passing them to md5()

$challenge = 'c731395aca5dcf45446c0ae83db5319e';
$uamsecret = 'secret';
$password = 'password';

$hexchal = pack ("H32", $challenge);
$newchal = pack ("H*", md5(utf8_encode($hexchal) . $uamsecret));
$response = md5("\0" . $password . utf8_encode($newchal));
$newpwd = pack("a32", $password);
$pappassword = implode ("", unpack("H32", ($newpwd ^ $newchal)));

echo "Response: ---> ", $response, "\n";
echo "New Password: ---> ", $newpwd, "\n";
echo "Pap Password: ---> ", $pappassword, "\n";

然后返回与Javscript相同的结果:

This then returns the same results as the Javscript:

Response: ---> fbfd42ffde05fcf8dbdd02b7e8ae2d90
New Password: ---> password
Pap Password: ---> dcbdacb03f5d38ca33c128b9310c272a



2.更改Javascript中的md5模块



2. Change the md5 module in Javascript

我假设您正在使用 bluimp JavaScript-MD5 模块,因为这就是它由您链接的DaloRADIUS例程使用.您可以对此打补丁以绕过UTF-8转换.

I am assuming you are using the bluimp JavaScript-MD5 module, as this is what it used by DaloRADIUS routine you linked. You can patch this to bypass the UTF-8 conversion.

您可以通过多种方式对此进行修补,但是在第259行是md5()函数本身的定义.这只是一组if语句,用于解析输入选项并调用适当的内部函数.

There are various ways you can patch this, but on line 259 is the definition of the md5() function itself. This is simply a set of if statements to parse the input options and call the appropriate internal function.

但是,此块调用的函数只是通过调用str2rstrUTF8()的函数来提供UTF-8输入转换,然后再调用适当的函数以提供实际的哈希.因此,您可能需要修补md5()以接受第三个参数,以指示是否应应用UTF-8转换,然后适当地调用其他函数.

However, the functions called by this block simply provide the UTF-8 input conversion, through a function called str2rstrUTF8() before then call the appropriate functions to provide the actual hashing. You may therefore want to patch the md5() to accept a third parameter to indicate whether the UTF-8 conversion should be applied and then call other functions as appropriate.

不过,要完全完全删除转换,更简单的方法是更改​​str2rstrUTF8()以使输入保持不变.可以在第239行找到此函数,将其更改为如下所示将停止转换:

However to simply remove the conversion completely the easier way is to change str2rstrUTF8() to return the input unchanged. This function can be found on line 239, changing it to just read as follows will stop the conversion:

function str2rstrUTF8 (input) {
  return input
}

或者,要删除冗余函数调用,也可以仅删除对其的引用.更改从第246行开始的功能,如下所示:

Alternatively to remove the redundant function call you can instead just remove the references to it. Change the function starting on line 246 to read as follows:

function rawMD5 (s) {
  return rstrMD5(s)
}

第252行的rawHMACMD5()函数还包括对str2rstrUTF8()函数的调用,您可能还想对其进行修补以保持一致性,但是上述例程不需要这样做.当传递第二个参数以提供密钥哈希(一种功能)时,将调用该函数在本机PHP md5()函数中不可用.

The rawHMACMD5() function on line 252 also includes calls to the str2rstrUTF8() function which you may also want to patch for consistency but this is not required for the above routine. That function is called instead when a second parameter is passed to provide a key hash, a feature not available in the native PHP md5() function.

进行上述任何更改后,Javascript例程现在将返回与原始PHP代码相同的输出(使用ISO-8859-1):

After making either of those changes the Javascript routine now returns the same output as your original (ISO-8859-1 using) PHP code:

Response: -->  – "2d4bd27184f5eb032641137f728c6043"
New Password: --> – "password������������������������"
Pap Password: ---> – "356a1fb08f909fc40dfe448fc483ce3"

这篇关于Javascript不匹配中的PHP Pack/Unpack实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆