AES 128位CTR部分文件的PHP解密

AES 128位CTR部分文件的PHP解密,php,encryption,cryptography,aes,http-range,Php,Encryption,Cryptography,Aes,Http Range,这不是一篇重复的帖子,因为我到处都找了,找不到答案。它是关于部分解密的。还没满 我对PHP有很好的了解,但对密码学知之甚少。 我知道加密文件的钥匙和iv。该文件整体解密效果良好,但当我试图从中间解密部分文件时,真正的问题出现了 当我尝试解密文件的前128kb或256kb或文件开头的任意长度时,它的解密效果很好。 但当我从中间开始时,它不会解密,而是给出乱七八糟的输出 我将在这里发布文件前100个字节的示例 加密为AES 128位CTR模式 我使用了PHP的mdecrypt_generic和mcr

这不是一篇重复的帖子,因为我到处都找了,找不到答案。它是关于部分解密的。还没满

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

当我尝试解密文件的前128kb或256kb或文件开头的任意长度时,它的解密效果很好。 但当我从中间开始时,它不会解密,而是给出乱七八糟的输出

我将在这里发布文件前100个字节的示例

加密为AES 128位CTR模式

我使用了PHP的mdecrypt_generic和mcrypt_解密函数,但没有成功

使用的代码:

$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=
$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==
如你所见。解密后,结果是文件的前100个字节,其中包含连续的数字1。 该文件由Mega.co.nz使用JavaScript加密。根据Mega的文档,该文件已被分块加密以进行部分加密/解密

文件加密

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

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

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

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

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


有可能吗?这应该是因为一些网站已经这样做了。

在我看来,您正在对区块边界进行大量计算(以表格形式给出+超过4608Ki的简单计算),而没有进行计算以获得新的IV

IV只是随机的nonce加上一个块计数器。因此,要计算特定区块的新“IV”,您必须执行以下操作:

  • 通过在较高(左)字节中移动nonce来创建初始计数器
  • 获取块的下边界
  • 将下边界除以块大小
  • 向初始计数器中添加或XOR(前2^64个块的结果相同)
  • 用它初始化密码

  • 然后你就可以解密了。

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

    while($_total_dled != $content_length) {
            $raw = fgets($socket, 1024);
            $data = mdecrypt_generic($this->cipher, $raw);
            echo $data;
    }
    
    但是,如果我从pos x开始读取文件(就像我收到:Range x-),mdecrypt_generic将失败,因为之前没有执行(x-1)次。 所以我试着这样做:

    for($i=0;$i<$range["start"];$i++) {
         mdecrypt_generic($this->cipher, "0");
    }
    
    for($i=0;$icipher,“0”);
    }
    
    只需解密一个字符(x-1)次。 然后是带有while循环的部分。它是有效的。 也许我们可以把这个迭代和相关的计数器联系起来


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

    从MEGA doc提供的信息来看,不清楚每个区块是单独加密的还是所有区块都被视为一个数据流。你能提供这类细节的链接吗?我同意文档非常模糊。这里是链接:您正在向我们显示大量字符的数据。不要那样做。以Base-64或十六进制(=Base-16)显示它们。当试图将字节数据表示为原始字符串时,可能会出现很多问题。可能出错的一个原因是字符“丢失”,例如:
    \r\n
    ->
    \n
    。请非常清楚您是在处理字节,而不是字符,并小心地在字节和Base-64之间进行翻译。@rossum感谢您指出这一点,您是对的。但是问题还是一样的,文件可以部分解密吗?从MEGA的文档中我了解到,该文件已逐块加密,并且也给出了块边界,但解密没有按预期进行。有没有其他方法可以做到这一点?我也尝试过在python的库中解密它,以及在PHP中使用一些其他定制的AES解密算法。使用CTR加密的文件可以逐块或逐块解密。块中的块应在计数器上按顺序运行。您需要联系加密端以确定如何在每个块的开始处设置加密:计数器(重新)从何处开始?使用什么临时数字?是否使用了新钥匙?所有区块开始条件