1

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

密钥采用 base64 加密:E7VQWj3cv1JUi5pklirtDQ9SRJt1DhiqYgzPSpIiVP0

超级文档:https ://mega.co.nz/#doc

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

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

IV 是通过在第 4 个偏移处以 2 的长度对数组进行切片而获得的,并且数组的最后两个元素用 0 填充:

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

然后对密钥进行异或并制成一个 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 个字节解密文件,但在此之前,我解密一个随机字符串或只是数字 0,然后从第 2 个字节开始解密。我想这与 IV 块计数器有关。我解密一个随机字节,然后继续解密实际的密码,这样它就可以工作了。我需要从一开始就开始解密文件,比如说从 40mb 偏移量来支持实时流搜索。但这会消耗太多内存,因为我必须先解密 40mb 的 0,然后才能进行搜索。如何将 IV 计数器值移动到 40mb 偏移量?

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

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

4

1 回答 1

0

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

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

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

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

您正在用 PHP 编写,但我正在发布一个来自我用 Java 编写的 Mega 下载程序的方法,以防万一:

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;
}
于 2014-10-06T11:40:01.630 回答