php xtea实现(cfb)

问题描述 投票:1回答:2

我遇到了一种我无法理解的怪异行为。

我使用mcrypt xtea(cfb模式)来加密一些数据。由于php 7.2正在摆脱mcrypt,因为openssl也不支持Xtea,所以我必须自己实现算法。

问题是,无论使用何种算法:

  • 我测试了这里提供的那个:pear implementation,它只是一个ECB模式(没有初始向量)
  • 在维基百科页面上提供的这个stackoverflow topic
  • 我在这里开发的(用于CFB模式)基于维基百科herehere以及可以找到的mcrypt源代码中的以下两篇文章here/* * $v is the data, $k is the 128bits key and $iv is 64bits init vector (size = 8) * Code is not optimized */ function encryptCfb($v, $k, $iv) { $v = array_values(unpack('N*', $v)); $iv = array_values(unpack('N*', $iv)); $k = array_values(unpack('N*', $k)); $cipher = []; //IV ciphering using the 128bits key list ($v0, $v1) = cipher($iv[0], $iv[1], $k); //Xoring the cipherd block with the first 64bits of data (32bits in V0 and 32 others in V1) $cipher[0] = $v0 ^ $v[0]; $cipher[1] = $v1 ^ $v[1]; for ($i=2; $i < count($v); $i+=2) { //Now ciphering the latest "cipherd" data using the 128bits key list ($y, $z) = cipher($cipher[$i-2], $cipher[$i-1], $k); //Xoring the cipherd block with the second 64bits of data (32bits in V0 and 32 others in V1) $cipher[$i] = $y ^ $v[$i]; $cipher[$i+1] = $z ^ $v[$i+1]; } $output = ""; foreach ($cipher as $i) { $output .= pack('N', $i); } return $output; } function cipher($v0, $v1, $k) { $delta=0x9e3779b9; $sum = 0; $limit = $delta * 32; for ($i=0; $i < 32; $i++) { $v0 += ((($v1<<4) ^ ($v1>>5)) + $v1) ^ ($sum + $k[$sum & 3]); $sum += $delta; $v1 += ((($v0 << 4) ^ ($v0 >> 5)) + $v0) ^ ($sum + $k[($sum>>11) & 3]); } return [$v0, $v1]; }

我得到了不同的结果,而且没有一个给出mcrypt给出的完全相同的结果:

$cryptModule = mcrypt_module_open('xtea', '', 'ncfb', '');
mcrypt_generic_init($cryptModule, $key, $iv);
mcrypt_generic($cryptModule, $data);

您可以使用相同的数据/密钥/ IV检查和测试我在此处进行的不同测试:

有谁知道为什么我得到不同的结果?

php encryption mcrypt xtea
2个回答
0
投票

有谁知道为什么我得到不同的结果?

我没有,但我怀疑所有旧的(2006年及以前的?)userland-php-implementation从未测试过,并且不适用于64位PHP。

我只需要在一个项目中使用XTEA,和你一样,我测试了所有其他可用的XTEA实现,它们都是very old,并且它们都没有产生正确的结果(我怀疑所有2006年和以前的实现从未测试过在64位系统上,它们不适用于64位系统)

长话短说,我从头开始在PHP中编写了一个64位兼容的XTEA实现,代码可以在这里找到:https://github.com/divinity76/php-xtea

例子

<?php 
require_once('XTEA.class.php');
$key_binary = "secret";
$keys_array = XTEA::binary_key_to_int_array($key_binary);
$data = "Hello, World!";
$encrypted = XTEA::encrypt($data, $keys_array);
$decrypted = XTEA::decrypt($encrypted, $keys_array);
var_dump($data, $encrypted, $decrypted);

应输出如下内容:

string(13) "Hello, World!"
string(16) "□□Jx□□□□□□□ܴ9"
string(16) "Hello, World!   "

长度是不同的,因为xtea长度填充,可以通过改为禁用

XTEA::encrypt($data, $keys_array, XTEA::PAD_NONE);

这会给你:

PHP Fatal error:  Uncaught InvalidArgumentException: with PAD_NONE the data MUST be a multiple of 8 bytes! in /cygdrive/c/projects/tibia_login_php/xtea.class.php:73
Stack trace:
#0 /cygdrive/c/projects/tibia_login_php/xtea_tests.php(8): XTEA::encrypt('Hello, World!', Array, 0)
#1 {main}
  thrown in /cygdrive/c/projects/tibia_login_php/xtea.class.php on line 73

因为XTEA算法要求数据加密为8字节的倍数。但如果我们改变它

<?php 
require_once('XTEA.class.php');
$keys_binary = "secret";
$keys_array = XTEA::binary_key_to_int_array($keys_binary);
$data = "Hello, World!123";
$encrypted = XTEA::encrypt($data, $keys_array, XTEA::PAD_NONE);
$decrypted = XTEA::decrypt($encrypted, $keys_array);
var_dump($data, $encrypted, $decrypted);

你会得到

string(16) "Hello, World!123"
string(16) "%t□□□n□□aʓ'□□H"
string(16) "Hello, World!123"
  • 没有填充,没有长度变化,也没有异常。

-1
投票

它应该与$ v0和$ v1上的模数一起使用:

function cipher($v0, $v1, $k) {
    $delta = 0x9e3779b9;
    $sum = 0;
    $limit = $delta * 32;

    for ($i=0; $i < 32; $i++) {
        $v0 += ((($v1<<4) ^ ($v1>>5)) + $v1) ^ ($sum + $k[$sum & 3]);
        $v0 = $v0 % pow(2, 32);
        $sum += $delta;
        $v1 += ((($v0 << 4) ^ ($v0 >> 5)) + $v0) ^ ($sum + $k[($sum>>11) & 3]);
        $v1 = $v1 % pow(2, 32);
    }

    return [$v0, $v1];
}

您还需要调整输入值$v的大小以确保其长度正确,例如使用您提到的PEAR模块_resize(&$data, $size, $nonull = false)Crypt_Xtea函数。

© www.soinside.com 2019 - 2024. All rights reserved.