php xtea implementation (cfb)



我来了一个我无法理解的怪异行为。

我正在使用McRypt XTEA(CFB模式)来加密一些数据。由于PHP 7.2摆脱了McRypt,并且由于OpenSSL也不支持XTEA,因此我必须自己实施该算法。

问题是,无论使用什么算法:

  • 我在此处测试了一个:梨实现仅是欧洲央行模式(无init vector)

  • 以及从此stackoverflow主题中获取的Wikipedia页面上提供的那个

  • 以及我在此处开发的(用于CFB模式)的一个基于以下两篇来自Wikipedia的文章,此处以及McRypt源代码可以在此处找到:

    /*
    * $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检查并测试我在此处进行的不同测试:

  • 我的实现与CFB模式下的MCRYPT。请注意:

    • 回合的数量什么都没有改变(32或64)
    • 使用N模式(大端)或V模式(小eNdian)的包装/解开包装,请更改
  • 梨欧洲央行模式与Mycrypt Ecb模式!

  • CBC模式中的Wiki代码与CBC模式中的McRypt中的MCRYPT!

有人知道为什么我会得到不同的结果吗?

有人知道为什么我会得到不同的结果吗?

我没有,但我怀疑所有旧的(2006年及以上?)Userland-php象征从未进行过测试,并且不适用于64位PHP。

我只需要在一个项目中使用XTEA,就像您一样,我测试了所有其他可用的XTEA实现,它们都是very old,它们都没有产生正确的结果(我怀疑所有2006年和所有较旧的实现从未在64位系统上进行测试,并且它们在64位系统上不起作用)

长话短说,我在scratch中写了一个64位兼容的Xtea-impluntion,可以在此处找到代码: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"
  • 没有填充,没有长度更改,也没有例外。

它应该在$ 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 Module Crypt_Xtea_resize(&$data, $size, $nonull = false)函数。

相关内容

  • 没有找到相关文章

最新更新