解密Mega.co.nz文件部分使用aes 128 ctr进行流媒体范围支持

时间:2014-10-05 17:57:19

标签: encryption cryptography streaming aes playready

如何从中间解密aes 128 ctr加密文件以获得http范围支持? 这是加密文件: https://www.dropbox.com/s/8e9qembud6n3z7i/encrypted.txt?dl=0

密钥是base64加密的:E7VQWj3cv1JUi5pklirtDQ9SRJt1DhiqYgzPSpIiVP0

Mega docs:https://mega.co.nz/#doc

通过解密给出数组的键来计算IV:

Array
(
    [0] => 330649690
    [1] => 1037877074
    [2] => 1418435172
    [3] => 2519395597
    [4] => 257049755
    [5] => 1963858090
    [6] => 1645006666
    [7] => 2451723517
)

通过将数组切片为长度为2的第4个偏移量来获得IV。数组的最后两个元素用0填充:

Array
(
    [0] => 257049755
    [1] => 1963858090
    [2] => 0
    [3] => 0
)

然后键被XOR'd并制成128位数组,然后通过php函数包转换为字符串:

 $key = array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]);
 $key = base64_encode(a32_to_str($key));
 $iv = base64_encode(a32_to_str($iv));

然后使用普通的php aes库解密文件。我正在使用mcrypt_generic进行解密过程。 当我尝试从第2个字节或第3个或中间解密文件时出现问题。 如果我从第1个字节解密它就可以正常工作。

我注意到的另一件事是,如果我从第二个字节解密文件,但在此之前,我解密一个随机字符串或只是数字0,解密工作从第二个字节开始。 我想它与IV块计数器有关。我解密一个随机字节然后继续解密实际的密码,以便它工作。 我需要从一开始就解密文件,让我们说从40mb的偏移量来支持直播搜索。 但这会占用太多内存,因为在完成搜索之前我必须解密40mb的0。 如何将IV计数器值移动到40mb偏移量

我读到每个块的IV增加+1以进行解密。但是因为我的IV是一个数组,所以如果我在其中添加1,我已经尝试了所有它不起作用。 我已经好几个月没有结果了。请帮忙

以下是我之前的问题,它帮助理解了这个过程:AES 128 bit CTR partial file decryption with PHP

1 个答案:

答案 0 :(得分:0)

您的初步研究确实是正确的。在CTR模式下,IV(或随机数)在每次加密操作后简单地递增1。 (加密和解密在CTR模式下是相同的操作,因此您可以根据需要将一个单词替换为另一个单词。)

换句话说,可以提前预测CTR模式密码的状态 - 只需将已加密的块数添加到初始IV中。特别是,该州不以任何方式依赖于明文。 AES的块大小为16,因此您可以添加加密的字节数除以16。

IV可以被认为是以大端存储的128位整数。您使用的加密API将其表示为包含四个32位整数的数组。在初始化密码之前,只需将块数添加到第四个整数即可。如果您认为您需要处理超过40亿个块左右,则需要将溢出处理添加到第三个整数。

稍微棘手的部分是将密码初始化为一个状态,在该状态下,您已经加密了一些不能被块大小整除的字节。解决方案是首先将密码初始化为已加密的字节数除以16,向下舍入,然后加密(已加密的字节数为mod 16)虚拟字节。我相信这实际上是你所怀疑的。

您正在使用PHP编写,但我在Mega下载程序中发布了一个方法,该程序是我用Java编写的,以防它有用:

public Cipher getDownloadCipher(final long startPosition) throws Exception {
    final Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
    final ByteBuffer buffer = ByteBuffer.allocate(16).put(nonce);
    buffer.asLongBuffer().put(startPosition / 16);
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(buffer.array()));
    final int skip = (int) (startPosition % 16);
    if (skip != 0) {
        if (cipher.update(new byte[skip]).length != skip) {
            //that should always work with a CTR mode cipher
            throw new IOException("Failed to skip bytes from cipher");
        }
    }
    return cipher;
}
相关问题