PHP异或函数实现"Length Not Match"
PHP XOR function implement "Length Not Match"
我在PHP中写了一个简单的异或函数。它独立运行时效果很好,但是当我将它实现到 class.
时,它总是抛出 "Length Not Match" 的异常
异或函数:
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;
}
我要实现的class:
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(不工作)
通过添加debug函数,终于发现问题不在XOR函数,而是在openssl_encrypt
函数。由于AES block size是16,我输入的刚刚好,函数会在明文中多填充一个block,导致输出加倍,所以才会出现这个错误。
解决方法很简单:把OPENSSL_RAW_DATA
改成OPENSSL_ZERO_PADDING
,函数就不会填充了。虽然这个问题解决了,但是现在需要我们手动填充消息,它会输出一个Base64编码的字符串。
如下更改所有 openssl_encrypt
,并根据需要替换第一个变量。
openssl_encrypt($firstBlock, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING);
我只想说:奇怪的设计
我在PHP中写了一个简单的异或函数。它独立运行时效果很好,但是当我将它实现到 class.
时,它总是抛出 "Length Not Match" 的异常异或函数:
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;
}
我要实现的class:
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(不工作)
通过添加debug函数,终于发现问题不在XOR函数,而是在openssl_encrypt
函数。由于AES block size是16,我输入的刚刚好,函数会在明文中多填充一个block,导致输出加倍,所以才会出现这个错误。
解决方法很简单:把OPENSSL_RAW_DATA
改成OPENSSL_ZERO_PADDING
,函数就不会填充了。虽然这个问题解决了,但是现在需要我们手动填充消息,它会输出一个Base64编码的字符串。
如下更改所有 openssl_encrypt
,并根据需要替换第一个变量。
openssl_encrypt($firstBlock, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING);
我只想说:奇怪的设计