草庐IT

javascript - PHP转JS密码加密算法抛异常

coder 2024-04-15 原文

下面是我必须用于我正在构建的控制面板的密码哈希算法。原始函数在 PHP 中,但我正在重写它以便在 JavaScript 中与 Node.js 一起使用。

一切似乎都很顺利,但随后我调用了 fMod 并发生了崩溃:

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

尽管使用其他值,fmod 函数似乎也能正常工作。我在 fMod 中标记了抛出异常的行。

密码的正确哈希值应该是:

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。

还有其他几种方法可以解决此问题。

请注意,Number.prototype.toFixed() 将在 p > 0 时抛出 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()

关于javascript - PHP转JS密码加密算法抛异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22651663/

有关javascript - PHP转JS密码加密算法抛异常的更多相关文章

  1. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  2. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  3. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  4. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  5. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  6. ruby - 使用 AES 的 Rails 加密,过于复杂 - 2

    我在加密来self正在使用的第三方供应商的值时遇到问题。他们的指令如下:1)Converttheencryptionpasswordtoabytearray.2)Convertthevaluetobeencryptedtoabytearray.3)Theentirelengthofthearrayisinsertedasthefirstfourbytesontothefrontofthefirstblockoftheresultantbytearraybeforeencryption.4)EncryptthevalueusingAESwith:1.256-bitkeysize,2.25

  7. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  8. ruby-on-rails - 在 Rails 中自定义 "Password confirmation doesn' t 匹配密码 - 2

    有没有办法在Rails中为确认字段自定义消息?例如在设计中我必须输入密码和password_confirmation并且错误消息是:Passwordconfirmationdoesn'tmatchPassword我可以更改事件记录语言环境消息(“不匹配”),但它会在该语言环境消息的开头和结尾输出密码确认和密码,所以我得到如下内容:"PasswordconfirmationmustmatchPassword"有没有办法将其更改为不同的字符串?PasswordconfirmationandPasswordmustmatch.编辑另一件事是拥有完全自定义的消息,例如:'Setpassword

  9. ruby - 如何捕获 ruby​​ 中的所有异常? - 2

    我们如何捕获或/和处理ruby​​中所有未处理的异常?例如,这样做的动机可能是将某种异常记录到不同的文件或发送电子邮件给系统管理。在Java中我们会做Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandlerex);在Node.js中process.on('uncaughtException',function(error){/*code*/});在PHP中register_shutdown_function('errorHandler');functionerrorHandler(){$error=error_

  10. ruby - Sinatra 中的全局救援和日志记录异常 - 2

    如何在出现异常时指定全局救援,如果您将Sinatra用于API或应用程序,您将如何处理日志记录? 最佳答案 404可以在not_found方法的帮助下处理,例如:not_founddo'Sitedoesnotexist.'end500s可以通过调用带有block的错误方法来处理,例如:errordo"Applicationerror.Plstrylater."end错误的详细信息可以通过request.env中的sinatra.error访问,如下所示:errordo'Anerroroccured:'+request.env['si

随机推荐