寻找 AES-CTR 加密的输入

Posted

技术标签:

【中文标题】寻找 AES-CTR 加密的输入【英文标题】:Seeking in AES-CTR-encrypted input 【发布时间】:2013-05-16 08:13:41 【问题描述】:

由于 CTR 模式下的 AES 非常适合随机访问,假设我在 AES-CTR 模式下使用 CipherOutputStream 创建了一个数据源。下面的库(不是我的)使用RandomAccessFile 允许查找文件中的特定字节偏移量。

我最初的想法是使用CipherInputStream 和使用正确参数初始化的Cipher,但the API for that 不进行搜索并且声明不支持markreset

我是否错过了可以为我执行此操作的 API 的一部分,我是否应该查看 CTR 的 IV/块计数器的配置并使用自定义输入流重新创建它(这听起来像猎枪瞄准 @ 987654328@ 给我)还是采取我错过的其他方法?

【问题讨论】:

【参考方案1】:

我最终查明了 IV 在 CTR 模式下是如何更新的。事实证明,它为它处理的每个 AES 块做一个简单的 +1。我按照以下思路实现了阅读。

给定一个实现read-like 方法的类,该方法将读取加密字节序列中的下一个字节,并且需要支持在该序列中查找和以下变量:

BLOCK_SIZE:固定为 16(128 位,AES 块大小); cipherjavax.crypto.Cipher的一个实例,初始化处理AES; delegate:一个java.io.InputStream,它封装了一个允许随机访问的加密资源; input: javax.crypto.CipherInputStream 我们将提供读取服务(流将负责解密)。

seek 方法是这样实现的:

void seek(long pos) 
    // calculate the block number that contains the byte we need to seek to
    long block = pos / BLOCK_SIZE;
    // allocate a 16-byte buffer
    ByteBuffer buffer = ByteBuffer.allocate(BLOCK_SIZE);
    // fill the first 12 bytes with the original IV (the iv minus the actual counter value)
    buffer.put(cipher.getIV(), 0, BLOCK_SIZE - 4);
    // set the counter of the IV to the calculated block index + 1 (counter starts at 1)
    buffer.putInt(block + 1);
    IvParameterSpec iv = new IvParameterSpec(buffer.array());
    // re-init the Cipher instance with the new IV
    cipher.init(Cipher.ENCRYPT_MODE, key, iv);
    // seek the delegate wrapper (like seek() in a RandomAccessFile and 
    // recreate the delegate stream to read from the new location)
    // recreate the input stream we're serving reads from
    input = new CipherInputStream(delegate, cipher);
    // next read will be at the block boundary, need to skip some bytes to arrive at pos
    int toSkip = (int) (pos % BLOCK_SIZE);
    byte[] garbage = new byte[toSkip];
    // read bytes into a garbage array for as long as we need (should be max BLOCK_SIZE
    // bytes
    int skipped = input.read(garbage, 0, toSkip);
    while (skipped < toSkip) 
        skipped += input.read(garbage, 0, toSkip - skipped);
    

    // at this point, the CipherStream is positioned at pos, next read will serve the 
    // plain byte at pos

注意这里省略了寻找委托资源,因为这取决于委托InputStream下面的内容。另请注意,初始 IV 需要从计数器 1(最后 4 个字节)开始。

单元测试表明这种方法是有效的(性能基准测试将在未来的某个时间进行:))。

【讨论】:

CTR 中的计数器应初始化为 0,如果它翻转,则可能会以相同的 nonce || CTR 值重用相同的密钥,这对安全性来说是灾难性的。您应该在此之前重新输入密钥。 你说得对,同时我已经稍微改变了我的实现以真正符合规范(不知道为什么我一开始没有找到/去做.. .) 嗯,我不会再编辑评论了。 A link to the buildup of the IV according to the spec. 根据我的观察,Oracle JDK 将整个 IV 字节序列作为一个大整数,而不仅仅是尾随的 32 位整数。
 字节[] ivBytes = 新字节[16]; Arrays.fill(ivBytes, (byte)-1); IvParameterSpec iv = new IvParameterSpec(ivBytes); cipher.init(Cipher.ENCRYPT_MODE, key, iv); cipher.update(新字节[16]);字节[] o2 = cipher.update(新字节[16]); Arrays.fill(ivBytes, (byte)0); iv = new IvParameterSpec(ivBytes); cipher.init(Cipher.ENCRYPT_MODE, key, iv);字节[] o3 = cipher.update(新字节[16]);断言.assertArrayEquals(o2, o3); 
> // 将 IV 的计数器设置为计算的块索引 + 1(计数器从 1 开始)这是不正确的t。 IV 是计数器,而不仅仅是最后四个字节。请参阅@fishautumn 中的示例> CTR 中的计数器应初始化为 0 这是不正确的。无论您在 [0 .. 2^128 - 1] 中的起始值如何,您都将在 2^128 步之后重新使用它。

以上是关于寻找 AES-CTR 加密的输入的主要内容,如果未能解决你的问题,请参考以下文章

text Jamf Pro EA检查加密。在T2芯片设备上寻找“加密”时很有用

aes加密安全吗

在java中加密和解密属性文件值

在 iOS 上使用私钥加密数据

Objective-C / iOS中的加密入门[关闭]

js加密(十四)mail.yw.gov.cn/ RSA