密码encryptionalgorithm在从PHP转换为JS时会抛出exception

以下是我正在构build的控制面板必须使用的密码哈希algorithm。 原来的function是在PHP中,但我正在重写它与JavaScript中的Node.js一起使用。

一切似乎都很顺利,但是我打电话给fMod并得到一个崩溃:

 RangeError: toFixed() digits argument must be between 0 and 20 

虽然使用其他值,但fmod函数似乎正常工作。 我在fMod出了引发exception的行。

正确的密码散列应该是:

 0x31c7296631df873d0891b7b77ae0c6c6 

码:

 // JavaScript Version var pass = "Cake99"; console.log(pCrypt2(pass)); function pCrypt2(plain) { var array_mul = [213119, 213247, 213203, 213821]; var array_add = [2529077, 2529089, 2529589, 2529997]; var dst = Array.apply(null, new Array(16)).map(Number.prototype.valueOf,0); var key = Array.apply(null, new Array(16)).map(Number.prototype.valueOf,0); for (var i = 0; i < plain.length; i++ ) { dst[i] = key[i] = ord(plain.substr(i, 1)); } var val = []; for (var i = 0; i <= 3; i++ ) { val[i] = fmod((key[i * 4 + 0] + key[i * 4 + 1] * 0x100 + key[i * 4 + 2] * 0x10000 + key[i * 4 + 3] * 0x1000000) * array_mul[i] + array_add[i], 4294967296 ); } for (i = 0; i <= 3; i++ ) { key[i * 4 + 0] = val[i] & 0xff; key[i * 4 + 1] = val[i] / 0x100 & 0xff; key[i * 4 + 2] = val[i] / 0x10000 & 0xff; key[i * 4 + 3] = val[i] / 0x1000000 & 0xff; } dst[0] = dst[0] ^ key[0]; for (var i = 1; i <= 15; i++ ) { dst[i] = dst[i] ^ dst[i - 1] ^ key[i]; } for (var i = 0; i <= 15; i++ ) { if (dst [i] == 0 ) { dst [i] = 0x66; } } var encrypted = "0x"; for (var i = 0; i <= 15; i++ ) { if (dst [i] < 16 ) { encrypted = encrypted + "0"; } encrypted = encrypted + dst[i].toString(16); } return (encrypted); } function ord(string) { // discuss at: http://phpjs.org/functions/ord/ // original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // bugfixed by: Onno Marsman // improved by: Brett Zamir (http://brett-zamir.me) // input by: incidence var str = string + '', code = str.charCodeAt(0); if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters) var hi = code; if (str.length === 1) { return code; // This is just a high surrogate with no following low surrogate, so we return its value; // we could also throw an error as it is not a complete character, but someone may want to know } var low = str.charCodeAt(1); return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; } if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate return code; // This is just a low surrogate with no preceding high surrogate, so we return its value; // we could also throw an error as it is not a complete character, but someone may want to know } return code; } function fmod(x, y) { // discuss at: http://phpjs.org/functions/fmod/ // original by: Onno Marsman // input by: Brett Zamir (http://brett-zamir.me) // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // example 1: fmod(5.7, 1.3); // returns 1: 0.5 var tmp, tmp2, p = 0, pY = 0, l = 0.0, l2 = 0.0; tmp = x.toExponential() .match(/^.\.?(.*)e(.+)$/); p = parseInt(tmp[2], 10) - (tmp[1] + '') .length; tmp = y.toExponential() .match(/^.\.?(.*)e(.+)$/); pY = parseInt(tmp[2], 10) - (tmp[1] + '') .length; if (pY > p) { p = pY; } tmp2 = (x % y); if (p < -100 || p > 20) { // toFixed will give an out of bound error so we fix it like this: l = Math.round(Math.log(tmp2) / Math.log(10)); l2 = Math.pow(10, l); return (tmp2 / l2) .toFixed(l - p) * l2; } else { return parseFloat(tmp2.toFixed(-p)); <<< ---- FAILS HERE --------- } } 

// PHP原始——————————–

 function encrypt( $plain ) { $array_mul = array ( 0 => 213119, 1 => 213247, 2 => 213203, 3 => 213821 ); $array_add = array ( 0 => 2529077, 1 => 2529089, 2 => 2529589, 3 => 2529997 ); $dst = $key = array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0 ); for ( $i = 0; $i < strlen ( $plain ); $i++ ) { $dst [ $i ] = $key [ $i ] = ord ( substr ( $plain, $i, 1 ) ); } for ( $i = 0; $i <= 3; $i++ ) { $val [ $i ] = fmod ( ( $key [ $i * 4 + 0 ] + $key [ $i * 4 + 1 ] * 0x100 + $key [ $i * 4 + 2 ] * 0x10000 + $key [ $i * 4 + 3 ] * 0x1000000 ) * $array_mul [ $i ] + $array_add [ $i ], 4294967296 ); } for ( $i = 0; $i <= 3; $i++ ) { $key [ $i * 4 + 0 ] = $val [ $i ] & 0xff; $key [ $i * 4 + 1 ] = $val [ $i ] / 0x100 & 0xff; $key [ $i * 4 + 2 ] = $val [ $i ] / 0x10000 & 0xff; $key [ $i * 4 + 3 ] = $val [ $i ] / 0x1000000 & 0xff; } $dst [ 0 ] = $dst [ 0 ] ^ $key [ 0 ]; for ( $i = 1; $i <= 15; $i++ ) { $dst [ $i ] = $dst [ $i ] ^ $dst [ $i - 1 ] ^ $key [ $i ]; } for ( $i = 0; $i <= 15; $i++ ) { if ( $dst [ $i ] == 0 ) { $dst [ $i ] = 0x66; } } $encrypted = "0x"; for ( $i = 0; $i <= 15; $i++ ) { if ( $dst [ $i ] < 16 ) { $encrypted .= "0"; } $encrypted .= dechex($dst[$i]); } return ( $encrypted ); } 

您正在传递-p为第111行parseFloat()的位数,在这部分代码中:

 .... if (p < -100 || p > 20) { // toFixed will give an out of bound error so we fix it like this: l = Math.round(Math.log(tmp2) / Math.log(10)); l2 = Math.pow(10, l); return (tmp2 / l2) .toFixed(l - p) * l2; } else { return parseFloat(tmp2.toFixed(-p)); } 

在评估时, -p等于-1

为了演示的目的,如果我们改变最后三行

 ... } else { for(var i=0; i<=20;i++) { console.log(parseFloat(tmp2.toFixed(i))); } //return parseFloat(tmp2.toFixed(-p)); } 

我们得到

 2529997 2529997 2529997 ... 2529997 2529997 2529997 

这是因为在第101行,你得到两个整数的模。

 tmp2 = (x % y); 

两个整数的模数在JavaScript中总是一个整数

因此, 对第112行的parseFloat()中的位数使用任何值将返回相同的值

 ... } else { var i = Math.floor(Math.random()*20); return parseFloat(tmp2.toFixed(i)); } 

并运行脚本:

 alain@vaio ~/dev/test % node script.js 0x31c7296631df873d0891b7b77ae0c6c6 alain@vaio ~/dev/test % node script.js 0x31c7296631df873d0891b7b77ae0c6c6 alain@vaio ~/dev/test % node script.js 0x31c7296631df873d0891b7b77ae0c6c6 alain@vaio ~/dev/test % node script.js 0x31c7296631df873d0891b7b77ae0c6c6 alain@vaio ~/dev/test % node script.js 0x31c7296631df873d0891b7b77ae0c6c6 alain@vaio ~/dev/test % node script.js 0x31c7296631df873d0891b7b77ae0c6c6 

所以是的,如果你只是处理整数,就会丢失减号,或者完全删除p。

还有几种方法可以解决这个问题。

请注意,当p > 0时, Number.prototype.toFixed()将引发RangeError。 由于p的计算方式,这发生在四舍五入或者有前导零时:

 > x = 12345; tmp = x.toExponential().match(/^.\.?(.*)e(.+)$/); p = parseInt(tmp[2], 10) - (tmp[1] + '').length; 0 > x = 1234567890123456789; tmp = x.toExponential().match(/^.\.?(.*)e(.+)$/); p = parseInt(tmp[2], 10) - (tmp[1] + '').length; 2 > x = 101000; tmp = x.toExponential().match(/^.\.?(.*)e(.+)$/); p = parseInt(tmp[2], 10) - (tmp[1] + '').length; 3 

您目前正在使用x:3626296650629732529077和y:4294967296调用fmod,结果为p = 1。

您可以修改fmod函数以拒绝负值:

 if (p < -100 || p > 20) { // toFixed will give an out of bound error so we fix it like this: l = Math.round(Math.log(tmp2) / Math.log(10)); l2 = Math.pow(10, l); return (tmp2 / l2) .toFixed(l - p) * l2; } else if ( p > 0 ) { return parseFloat(tmp2.toFixed(p)); } else { return parseFloat(tmp2.toFixed(-p)); } 

我们修改你的pCrypt2函数来使用更小的x。

有关JavaScript舍入的更多详细信息,请参阅Number.prototype.toFixed() 。

更换:

 return parseFloat(tmp2.toFixed(-p)); 

有:

 return parseFloat(tmp2.toFixed(p)); 

http://jsfiddle.net/rd13/7UHdw/