这不是一个重复的帖子,因为我已经到处看了,我找不到这个问题的答案。它是关于部分解密的。不完整。
我对PHP有很好的了解,但对密码学知之甚少。我知道加密文件的密钥和iv。文件作为整体解密很好,但当我试图从中间解密部分文件时,真正的问题出现了。
当我尝试解密文件的第一个128kb或256kb或从文件开始的任何长度时,它会解密。但是当我从中间开始时,它不会解密,而是给出乱码输出。
我将在这里发布一个文件的前100个字节的例子。
加密方式为AES 128 bit 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/。(每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;
}
我已经尝试单独解密第二个块,它失败了。由于显而易见的原因,我不能在这里发布一个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范围标头请求。如果范围请求落在第二个或第三个块中,我需要能够解密该块并将其发送到客户端,而无需从头解密文件。
这可能吗?应该是因为有些网站已经这么做了
好了,我找到了动态解密部分内容的解决方案。当我试图从范围解密部分数据(为了创建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");
}
只需要解密一个字符(x-1)次。然后是while循环的部分。这是有效的。也许我们可以把这个迭代和相关的计数器连接起来。
在我看来,您正在对块边界(作为表+ 4608Ki的简单计算)进行大量计算,并且没有计算以获得新的IV。
IV只是随机的nonce加上一个块计数器。因此,要为特定块计算新的"IV",您必须执行:
- 通过移动较高(左)字节的nonce来创建初始计数器
- 获取块下边界
- 将下边界除以块大小
- 将结果数添加或异或(前2^64块相同)到初始计数器
- 用它初始化密码