在Javascript不匹配的PHP包/解压缩实现

根据这个问题的相关答案 ,我试图把类似这个PHP进程的pack / unpack解决scheme放在一起,但是在使用md5和bufferpack的 Nodejs(Javascript)中

这里是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格式

以明文forms:

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

以上所有的片段都可以在这里find: RadiusNES

我在这整个过程中的理解并不是最好的,并且会感谢见解和我出错的地方。

为什么有一个不匹配?

翻译不起作用,因为PHP包函数使用不同的格式string并返回string,而JavaScript缓冲区模块返回数组。 你也不能在Javascript中使用string。

虽然可能有模块来做你想做的,我有我自己的函数来parsinghexstring。 我也喜欢修改不是每个人都同意的原型,但是这些原型可以转换为常规function。

 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原型中定义了两个函数来replacepack函数的使用:

.pad( 32, string )用于填充空string以得到与pack( 'a32', string )相同的结果。 尽pipe这里不需要,但是如果想要将stringi填充为除了空值以外的字符,还需要第二个参数。

.packHex相当于pack( 'H*' ,string ) ,并将每对hex字符的代码翻译成一个字符。 理想情况下,函数需要更多的validation来testingstring是一个有效的hex,如果要使用。

在input定义之后,接下来的四行代替使用这些函数设置variables而不是pack

因为Javascript本身不能原生异或string,所以需要使用循环来提取每个字符,将其转换为数字,然后将这些值转换为字符以创buildpappasswordstring。

对我来说,这将会回来:

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

这是一个结果,但不幸的是从PHP代码不同。

这是因为我的PHP安assembly置为在内部使用ISO-8859-1编码,而Javascript原生使用UTF-16。

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

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

因为我们知道hexstring是一个字节,所以Javascript正在使用UTF-8,所以PHP可以通过使用utf8_encode()函数在打包hexstring之前转换压缩的hexstring。

原来我以为JavaScript是内部转换编码的hex字符为他们的unicode等值,因为这一点,但事实并非如此。 相反,它是在Javascript中使用的md5模块,它正在对input执行UTF-8转换。

这留下了两个可能的select。

1.使用UTF-8 PHP

如果可能,您可以重新configuration您的PHP服务器以使用UTF-8编码。 或者你可以改变你的脚本来使用utf8_encode()函数来镜像与Javascript中发生的相同的过程,并在将hex压缩string传递给md5()之前将其转换为UTF-8。

 $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语句来parsinginput选项并调用相应的内部函数。

然而,这个块所调用的函数只是在调用相应的函数来提供实际的散列函数之前,通过一个名为str2rstrUTF8()的函数来提供UTF-8的input转换。 因此,您可能需要修补md5()以接受第三个参数,以指示是否应该应用UTF-8转换,然后根据需要调用其他函数。

但是,要简单地完全删除转换,更简单的方法是更改str2rstrUTF8()以返回input不变。 这个函数可以在第239行find,把它改为只读如下将停止转换:

 function str2rstrUTF8 (input) { return input } 

也可以删除多余的函数调用,而只是删除对它的引用。 将行246上开始的函数更改为如下所示:

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

第252行中的rawHMACMD5()函数还包含对str2rstrUTF8()函数的调用,您可能还需要对其进行修补以保持一致性,但以上例程不需要此操作。 当传递第二个参数来提供密钥散列时 ,会调用该函数,而本地PHP md5()函数中则不提供该function。

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

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