Javascript中的PHP打包/解包实现不匹配

Javascript中的PHP打包/解包实现不匹配,javascript,php,node.js,Javascript,Php,Node.js,根据,我正试图在Nodejs(Javascript)中使用和组合一个类似于这个PHP过程的打包/解包解决方案 以下是PHP方法(改编自: 上述情况与这些情况相呼应: 以上为纯文本: Response: ---> 2d4bd27184f5eb032641137f728c6043 New Password: ---> password Pap Password: ---> 356a1fb08f909fc400dfe448fc483ce3 Response: --> e8

根据,我正试图在Nodejs(Javascript)中使用和组合一个类似于这个PHP过程的打包/解包解决方案

以下是PHP方法(改编自:

上述情况与这些情况相呼应:

以上为纯文本:

Response: ---> 2d4bd27184f5eb032641137f728c6043
New Password: ---> password
Pap Password: ---> 356a1fb08f909fc400dfe448fc483ce3
Response: -->  e8a54a55cbcd81dbc2bdfd9b197d62af
New Password: --> <Buffer >
Pap Password: ---> NaN
在Javascript中,我现在要做的是:

  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: ---> 2d4bd27184f5eb032641137f728c6043
New Password: ---> password
Pap Password: ---> 356a1fb08f909fc400dfe448fc483ce3
Response: -->  e8a54a55cbcd81dbc2bdfd9b197d62af
New Password: --> <Buffer >
Pap Password: ---> NaN
响应:-->e8a54a55cbcd81dbc2bdfd9b197d62af
新密码:-->
Pap密码:-->NaN
以上所有代码片段都可在此处找到:

我对整个过程的理解并不是最好的,我会很欣赏我的见解和我的错误所在


为什么不匹配?

转换不起作用,因为使用不同的格式字符串和返回字符串,而返回数组。此外,您不能在Javascript中对字符串进行异或

虽然可能有一些模块可以做你想做的事情,但我有自己的解析十六进制字符串的函数。我也喜欢修改原型,虽然不是每个人都同意,但这些原型可以转换为常规函数

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);
这是一个结果,但不幸的是与PHP代码不同

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

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

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

因为我们知道十六进制字符串将是一个字节,Javascript有效地使用UTF-8,所以PHP可以通过使用
utf8\u encode()
函数在md5ing之前转换压缩的十六进制字符串来实现同样的功能

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

这就留下了两种可能的选择


1.使用UTF-8 PHP

如果可能,您可以重新配置PHP服务器以使用UTF-8编码。或者您可以更改脚本以使用
utf8\u encode()
函数来镜像Javascript中正在发生的相同过程,并将十六进制压缩字符串转换为UTF-8,然后再将其传递到
md5()

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

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


2.更改Javascript中的md5模块

我假设您正在使用该模块,因为这是您链接的DaloRADIUS例程所使用的。您可以对此进行修补以绕过UTF-8转换

有多种方法可以对此进行修补,但第259行是
md5()
函数本身的定义。这只是一组
if
语句,用于解析输入选项并调用相应的内部函数

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

但是,要完全删除转换,更简单的方法是更改
str2rstrUTF8()
以返回未更改的输入。可以在第239行找到此函数,将其更改为仅读取如下内容将停止转换:

function str2rstrUTF8 (input) {
  return input
}
或者,要删除冗余函数调用,您可以只删除对它的引用。将第246行开始的函数更改为:

function rawMD5 (s) {
  return rstrMD5(s)
}
第252行上的
rawHMACMD5()
函数还包括对
strstrutf8()
函数的调用,您可能还希望对该函数进行一致性修补,但上述例程并不需要该函数。当传递第二个参数以提供一个在本机PHP
md5()中不可用的特性时,将调用该函数
功能

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

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

只要可能,请尝试在问题正文中以格式化代码的形式发布纯文本。这些截图对于某些人来说即使不是不可能也很难阅读:它们依赖于屏幕阅读器或翻译工具。@tadman Okay,很快就会更新。这没什么大不了的,但通过键入长哈希来重现结果是不可能的这对任何人来说都不是一件有趣的事。我认为你需要更仔细地观察你用来组合你的反应的前体成分,
hexchal
newchal
,以确保它们在两面都是一样的。@tadman我更新了问题,并将更仔细地查看
hexchal
newchal
检查MD5个第一个值。我认为PHP可能会0字节(
NULL
)填充字符串,JavaScript可能会截断。有没有办法将我的JavaScript配置为使用ISO-8859-1编码,而不是将PHP更改为使用UTF?密码会发送到网络访问服务器(路由器)运行chillispot软件,该软件期望从未更改的PHP获得准确的响应。因此,有没有办法更改Javascript上的编码以匹配准确的响应?是的!我现在没有时间更新答案,但会在早上更新。基本上,虽然我认为是Javascript将压缩的十六进制字符串转换为UTF,但实际上,它没有使用字符代码,取而代之的是md5模块c
Response: -->  – "2d4bd27184f5eb032641137f728c6043"
New Password: --> – "password������������������������"
Pap Password: ---> – "356a1fb08f909fc40dfe448fc483ce3"