首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >修改后的PHP MD5提供不同的散列

问修改后的PHP MD5提供不同的散列
EN

Stack Overflow用户
提问于 2013-06-30 20:07:09
回答 1查看 618关注 0票数 1

我有一个修改过的MD5哈希函数,我在VB.NET和PHP中使用。当我在本地服务器(WAMP)上运行PHP代码时,我得到了与VB版本不同的结果。我尝试在phpfiddle上运行脚本,结果与VB版本相同。

我认为问题可能在于我在WAMP服务器上的PHP设置?

如果我在运行WAMP的PC上运行下面的脚本,我得到的结果是:

e5c35f7c3dea80fc68a4031582f34c25

当我在phpfiddle或php沙箱上运行完全相同的脚本时,我得到的结果是(这是预期的结果):

6337a43e8cd36058e80ae8cb4f465998

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-01 00:39:46

暂且抛开你在这里所做的事情听起来像是一个糟糕的方法--不管实际问题是你想要解决的是什么--以下是对这个问题的直接回答。

正如我在上面的注释中所描述的,问题的根本原因是PHP没有无符号整数的概念,它通过将溢出整数边界的数字转换为浮点数(这对按位操作不太好)来处理。这意味着,在32位系统上,您的代码将不能正常工作,因为MD5使用无符号32位整数。

您需要确保您的代码是“二进制安全的”,这样所有的数字都被表示为无符号32位整数。

要做到这一点,您需要重新实现加法操作符,以及(用当前实现) bindec()/hexdec()函数。值得注意的是,您当前处理某些过程的方法效率很低--所有转换到/从十六进制字符串的方法,以及二进制表示为ASCII字符串的位置--但现在我将在向您展示如何快速修复当前实现时对此进行说明。

首先,让我们看看加法操作:

代码语言:javascript
复制
private function binarySafeAddition($a, $b)
{
    // NB: we don't actually need 64 bits, theoretically we only need 33
    // but 40 bit integers are confusing enough, and 33 bits is unrepresentable
    $a = "\x00\x00\x00\x00" . pack('N', $a);
    $b = "\x00\x00\x00\x00" . pack('N', $b);

    $carry = $a & $b;
    $result = $a ^ $b;

    while ($carry != "\x00\x00\x00\x00\x00\x00\x00\x00") {
        $shiftedcarry = $this->leftShiftByOne($carry);
        $carry = $result & $shiftedcarry;
        $result ^= $shiftedcarry;
    }

    return current(unpack('N', substr($result, 4)));
}

private function leftShiftByOne($intAsStr)
{
    $p = unpack('N2', $intAsStr);
    return pack('N2', ($p[1] << 1) | (($p[2] >> 31) & 0x00000001), $p[2] << 1);
}

private function add()
{
    $result = 0;

    foreach (func_get_args() as $i => $int) {
        $result = $this->binarySafeAddition($result, $int);
    }

    return $result;
}

这个例行公事的真正细节是无耻地从这里偷来的。还有一个帮助函数来执行左移位,因为PHP不允许左移字符串,还有一个方便的包装函数,它允许我们在一个干净的调用中将任意数量的操作数一起添加。

接下来让我们看一下bindec()和hexdec()替代品:

代码语言:javascript
复制
private function binarySafeBinDec($bin)
{
    $bits = array_reverse(str_split($bin, 1));
    $result = 0;

    foreach ($bits as $position => $bit) {
        $result |= ((int) $bit) << $position;
    }

    return $result;
}

private function binarySafeHexDec($hex)
{
    $h = str_split(substr(str_pad($hex, 8, '0', STR_PAD_LEFT), -8), 2);
    return (hexdec($h[0]) << 24) | (hexdec($h[1]) << 16) | (hexdec($h[2]) << 8) | hexdec($h[3]);
}

希望这些都是合理的不言自明的,但可以自由地询问任何你不明白的事情。

我们还需要用二进制安全实现替换所有的0xffffffff十六进制文本,因为这也会导致32位系统上的浮点。下面是一种安全的方法,可以在32位和64位系统上获得最适合的32位整数设置:

代码语言:javascript
复制
private $right32;

public function __construct()
{
    $this->right32 = ~((~0 << 16) << 16);
}

还有一个我们需要重新实现的方法,那就是rotate()。这是因为它使用了右移位,而这会将符号位的副本从右边移开。这意味着旋转块的左边将结束所有它的位设置,这显然不是我们想要的。我们可以通过创建一个仅为右侧集设置目标位的数字,并使用它创建一个ANDing右侧操作数来克服这一问题:

代码语言:javascript
复制
private function rotate ($decimal, $bits)
{
    return dechex(($decimal << $bits) | (($decimal >> (32 - $bits)) & (~(~0 << $bits) & $this->right32)));
}

当你把所有这些放在一起的时候,你就会想到像这这样的东西,它适用于32位和64位系统。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17394379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档