当前位置:  开发笔记 > 编程语言 > 正文

Javascript Mismatch中的PHP Pack/Unpack实现

如何解决《JavascriptMismatch中的PHPPack/Unpack实现》经验,为你挑选了1个好方法。

根据这个问题的相关答案,我试图整理一个类似于这个PHP进程的打包/解包解决方案,但是在Nodejs(Javascript)中使用md5和bufferpack

这是PHP方法(改编自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";

以上回声如下:

回应PHP

以明文为准:

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

在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);

结果如下:

响应Javascript

在JSON中:

响应Javascript JSON格式

在明文中:

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

以上所有代码段均可在此处获得:RadiusNES

我在整个过程中的理解并不是最好的,并且会欣赏见解以及我出错的地方.

为什么会出现不匹配?



1> Michael..:

转换不起作用,因为PHP Pack函数使用不同的格式字符串并返回字符串,而Javascript bufferpack模块返回数组.你也不能在Javascript中xor字符串.

虽然可能有模块可以执行您想要的操作,但我有自己的函数来解析十六进制字符串.我也喜欢修改并非每个人都同意的原型,但这些原型可以转换为常规功能.

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函数的使用:

.pad( 32, string )用于填充带有空值的字符串以提供与之相同的结果pack( 'a32', string ).虽然这里不需要它,但是如果想要用除空值之外的字符填充字符串,它还需要第二个参数.

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

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

因为Javascript本身不能xor字符串,所以你需要使用循环来提取每个字符,将其转换为数字,xor这些值,然后将结果转换回字符以创建pappassword字符串.

对我来说,这将会回归:

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

这是一个结果,但不幸的是与PHP代码不同.

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

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

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

因为我们知道十六进制字符串将是一个字节,Javascript实际上是使用UTF-8,所以PHP可以通过使用该utf8_encode()函数在md5ing之前转换打包的十六进制字符串来做同样的事情.

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

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


1.使用UTF-8 PHP

如果可能,您可以重新配置PHP服务器以使用UTF-8编码.或者您可以更改脚本以使用该utf8_encode()函数镜像Javascript中发生的相同过程,并将十六进制打包字符串转换为UTF-8,然后再将其传递给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相同的结果:

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



2.在Javascript中更改md5模块

我假设您正在使用bluimp 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)
}

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

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

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


更新了,我希望答案有意义.修补非常简单,但有各种应用方式,这取决于个人喜好.
推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有