PHP XOR函数实现"长度不匹配"

时间:2016-03-22 05:33:19

标签: php xor

我在PHP中编写了一个简单的XOR函数。它可以很好地独立运行,但它总是抛出“长度不匹配”#34;当我把它实现到一个类中时。

XOR功能:

private static function strxor($dataA, $dataB) {
    if (($dataLen = strlen($dataA)) != strlen($dataB)) {
        throw new Exception("Length Not Match in strxor");
    }
    $result = '';
    for ($i = 0; $i < $dataLen; $i++) {
        $result .= $dataA[$i] ^ $dataB[$i];
    }
    return $result;
}

我甚至尝试了从 Encrypt/decrypt with XOR in PHP 复制的另一个版本,并添加了长度检查和变量名称。

private static function xor_this($dataA, $dataB) {
    if (($dataLen = strlen($dataA)) !== strlen($dataB)) {
        die("Length Not Match in xor_this");
    }
    $result = '';
    for($i=0;$i<$dataLen;) {
        for($j=0;($j<$dataLen && $i<$dataLen);$j++,$i++) {
            $result .= $dataA{$i} ^ $dataB{$j};
        }
    }
    return $result;
}

我要上班的课程:

public static function encrypt($key, $data) {
    $iv = parent::genSafeRandomBytes(16);
    $nonce = parent::genSafeRandomBytes(16);
    $firstBlock = self::xor_this($nonce, $iv);
    $salt = parent::genSafeRandomBytes(16);
    $hmac = parent::signText($data, $key);
    $subkey = parent::genSubKey($key, $salt);
    $data = self::pkcs7pad($data);
    $data = str_split($data, 16);
    $tmp_r = openssl_encrypt($firstBlock, self::CIPHER, $subkey, OPENSSL_RAW_DATA);
    $result = '';
    for ($i = 0; $i < count($data); $i++) {
        $tmp_n = parent::ivAdd($nonce, $i+1);
        $tmp_n = self::xor_this($tmp_n, $tmp_r);
        $tmp_x = openssl_encrypt($tmp_n, self::CIPHER, $subkey, OPENSSL_RAW_DATA);
        $result .= $tmp_r = self::xor_this($tmp_x, $data[$i]);
    }
    return Base62::encode($iv.$nonce.$salt.$hmac.$result);
}

我确定这两个值的长度相同。我该如何解决?我真的不知道错误发生的原因和方式。

完整来源:https://gist.github.com/hartmantam/39857700831591775b1c(不工作)

1 个答案:

答案 0 :(得分:0)

通过添加调试函数,我终于发现问题不在XOR函数中,而是在openssl_encrypt函数中。由于AES块大小为16并且我输入恰到好处,该函数将向明文填充一个块,导致输出加倍,因此这就是发生此错误的原因。

解决方案非常简单:将OPENSSL_RAW_DATA更改为OPENSSL_ZERO_PADDING,然后该函数不会执行填充。虽然这个问题已经解决,但现在需要我们手动填充消息,它将输出一个Base64编码的字符串。

如下所示更改所有openssl_encrypt,并在需要时替换第一个变量。

openssl_encrypt($firstBlock, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING);

我只想说:奇怪的设计