使用PHP进行AES 128位CTR部分文件解密

时间:2014-07-18 00:05:31

标签: php encryption cryptography aes http-range

这不是一个重复的帖子,因为我到处寻找,我无法找到答案。它关于部分解密。不满。

我对PHP有很好的了解,但对密码学知之甚少。 我知道加密文件的密钥和iv。该文件整体解密很好但是当我尝试从中间解密部分文件时出现了真正的问题。

当我尝试解密文件的第一个128kb或256kb或文件开头的任何长度时,它会解密。 但是当我从中间开始时,它不会解密但会产生乱码。

我将在此处发布该文件的前100个字节的示例。

加密是AES 128位CTR模式。

我使用了PHP的mdecrypt_generic和mcrypt_decrypt函数但没有成功。

使用的代码:

$chunk2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, base64_decode($mega_key), $data, 'ctr', base64_decode($mega_iv));
echo base64_encode($data) .'<br />'. base64_encode($chunk2);

结果:

9PX2fU83NF3hLc+HFdyHkqfxC4bHWKUQwQHJkNVnYbKCIQrhlHvTKtz8T3Bb0TgBkyBoGHnDCzZs3bu54KLQ8Bv0lzrTVJbzJY5msBfcy7Zi2Z/fLoMm+nvqdGPTNR0uwv45xJ8=
MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE=

如你所见。解密后,结果是包含数字1 的文件的前100个字节。 该文件由Mega.co.nz使用JavaScript加密。根据Mega的文档,该文件已经被加密成块以进行部分加密/解密。

  

文件加密

     

MEGA使用客户端加密/解密来端到端保护文件传输和存储。从客户收到的数据被逐字存储和传输;   服务器既不解密也不重新加密,也不验证传入用户文件的加密。所有加密处理都在最终用户的控制之下。   为了允许完整性检查的部分读取,文件被视为一系列块。为简化服务器端处理,部分上载只能启动和   结束一个块边界。此外,部分下载只有在满足相同标准时才能进行完整性检查。块边界位于   以下位置:0 / 128K / 384K / 768K / 1280K / 1920K / 2688K / 3584K / 4608K /。 (每1024 KB)/ EOF

我正在用这个函数计算文件的块边界:

public function get_chunks($size)
{
    $chunks = array();
    $p = $pp = 0;

    for ($i = 1; $i <= 8 && $p < $size - $i * 0x20000; $i++) {
        $chunks[$p] = $i * 0x20000;
        $pp = $p;
        $p += $chunks[$p];
    }

    while ($p < $size) {
        $chunks[$p] = 0x100000;
        $pp = $p;
        $p += $chunks[$p];
    }

    $chunks[$pp] = ($size - $pp);
    if (!$chunks[$pp])
    {
        unset($chunks[$pp]);
    }

    return $chunks;
}

我试过单独解密第二个块,但它失败了。 出于显而易见的原因,我不能在这里发布一个128kb的块,但是我将向你显示从第2个字节到第100个字节的块。 这是使用相同代码的结果:

使用的代码:

$chunk2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, base64_decode($mega_key), $data, 'ctr', base64_decode($mega_iv));
echo base64_encode($data) .'<br />'. base64_encode($chunk2);

结果:

9fZ9Tzc0XeEtz4cV3IeSp/ELhsdYpRDBAcmQ1WdhsoIhCuGUe9Mq3PxPcFvROAGTIGgYecMLNmzdu7ngotDwG/SXOtNUlvMljmawF9zLtmLZn98ugyb6e+p0Y9M1HS7C/jnEnw==
MDK6A0kyWI3903mj+GokBGfLvHCuzITg8flodIM34gGSGtpE3pnIxxGCDhq72AijgnlBUIv5DGuAVzNoc0MR2t5SnNi281TnmtnnlvomTOWKd3HAnJTtsKCvJoHXGQLdDfbMag==

结果与mcrypt_module_open('rijndael-128', '', 'ctr', '');

相同

我需要部分解密文件,因为我正在尝试为Mega编写一个支持并行连接/恢复支持的开源下载管理器。

我需要动态解密文件以允许文件流,因此在下载后解密是不可能的。

在mega的网站上,他们自己的下载界面使用多个连接并以块的形式下载文件,还有另一个Web服务允许通过多个连接从Mega下载并恢复支持。

我需要解密部分文件以支持来自浏览器/下载管理器的HTTP Range标头请求。如果范围请求落在第二或第三个块中,我需要能够解密该块并将其发送到客户端而无需从头开始解密文件。

甚至可能吗?应该是因为某个网站已经完成了它。

2 个答案:

答案 0 :(得分:1)

好的,我找到了关于动态解密部分内容的解决方案。 当我尝试从Range解密部分数据时(我为了创建Web代理),我遇到了这个问题。 我发现如果我下载整个文件(从位置0这样),就没有问题了。 示例:

while($_total_dled != $content_length) {
        $raw = fgets($socket, 1024);
        $data = mdecrypt_generic($this->cipher, $raw);
        echo $data;
}

但是,如果我开始从 pos x 读取文件(就像我收到:范围x-),mdecrypt_generic将失败,因为它没有被执行(x-1)以前的时间。 所以我试试这个:

for($i=0;$i<$range["start"];$i++) {
     mdecrypt_generic($this->cipher, "0");
}

只需解密一个字符(x-1)次。 然后,带有while循环的部分。它有效。 也许我们可以将这个迭代与相关的计数器联系起来。

希望这会对人们有所帮助。

答案 1 :(得分:0)

在我看来,你正在对块边界进行大量计算(以表格+ 4608Ki的简单计算方式给出)并且无需计算以获得新的IV。

IV只是随机nonce加上一个块计数器。所以计算一个新的&#34; IV&#34;对于你需要做的特定块:

  1. 通过移动较高(左)字节
  2. 中的随机数来创建初始计数器
  3. 获得大块下边界
  4. 将下边界除以块大小
  5. 将结果数字添加或XOR(前两个^ 64块相同)到初始计数器
  6. 用它初始化你的密码
  7. 然后你应该可以解密。