在android中使用AES CTR模式随机访问InputStream [英] Random access InputStream using AES CTR mode in android

查看:25
本文介绍了在android中使用AES CTR模式随机访问InputStream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找不到用于随机访问的 AES CTR 加密的任何工作示例.有人可以指导我如何在 CTR MODE 中使用计数器以及如何实现跳转到流中的特定位置吗?

I am unable to find any working example for AES CTR encryption for random access. Can someone guide me how to use the counter in CTR MODE also how to implement jumping to a specific position in the stream?

默认流实现 (CipherInputStream) 不会跳过流并且会破坏纯文本.

The default stream implementation (CipherInputStream) doesn't skip the stream and it corrupts the plain text.

我正在尝试解密存储在 Android sdcard 上的加密视频文件.嵌入式 HTTP 文件服务器会动态解密它.一切正常,直到用户在视频中执行搜索:视频立即停止,因为它收到损坏的视频流.

I am trying to decrypt encrypted Video file stored on sdcard in Android. An embedded HTTP file server decrypts it on the fly. Everything is working fine until a user performs a seek within the video: the video stops immediately because it receives corrupt video stream.

我使用以下代码来初始化和加密/解密流(为了简单起见,我对密钥进行了硬编码.在生产中不会对其进行硬编码)

I am using following code to initialize and encrypt/ decrypt stream (for sake of simplicity i hard coded the keys. it will not be hard coded in production)

    ByteBuffer bb = ByteBuffer.allocate(16);
    bb.put("1234567891230000".getBytes());
    byte[] ivString = bb.array();

    // INITIALISATION
    String keyString = "1234567812345678";
    IvParameterSpec iv = new IvParameterSpec(ivString);
    SecretKeySpec keySpec = new SecretKeySpec(keyString.getBytes(), "AES");

    // FOR ENCRYPTION
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivString));
    Inputstream encrypted_is = new CipherInputStream(in, cipher);

    // FOR DECRYPTION
    cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivString));
            Inputstream decrypted_is = new CipherInputStream(in, cipher);

推荐答案

您不应该使用流来实现这一点.流用于顺序访问数据.跳过应该只用于向前跳跃短距离,标记/重置仅用于向后跳跃小距离.

You should not implement this using a stream. A stream is used for sequential access to data. Skipping should only be used for jumping short distances forward and mark/reset only for jumping small distances back.

使用文件 map 可能是最有效的.对于稍微简单但效率较低的方法,您可以使用 RandomAccessFile 代替.您还应该使用 Cipher.getInstance("AES/CTR/NoPadding") 使用IV",该IV"设置为您在文件中开始位置的预期计数器.

Using a file map is probably the most efficient. For a slightly easier approach but less efficient approach you could use RandomAccessFile instead. You should furthermore use Cipher.getInstance("AES/CTR/NoPadding") using an "IV" that is set to the counter you expect at the location you start within the file.

使用带有偏移量的点击率的示例代码:

Sample code for using CTR with offset:

private static final int AES_BLOCK_SIZE = 16;

public static final void jumpToOffset(final Cipher c,
        final SecretKey aesKey, final IvParameterSpec iv, final long offset) {
    if (!c.getAlgorithm().toUpperCase().startsWith("AES/CTR")) {
        throw new IllegalArgumentException(
                "Invalid algorithm, only AES/CTR mode supported");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("Invalid offset");
    }

    final int skip = (int) (offset % AES_BLOCK_SIZE);
    final IvParameterSpec calculatedIVForOffset = calculateIVForOffset(iv,
            offset - skip);
    try {
        c.init(Cipher.ENCRYPT_MODE, aesKey, calculatedIVForOffset);
        final byte[] skipBuffer = new byte[skip];
        c.update(skipBuffer, 0, skip, skipBuffer);
        Arrays.fill(skipBuffer, (byte) 0);
    } catch (ShortBufferException | InvalidKeyException
            | InvalidAlgorithmParameterException e) {
        throw new IllegalStateException(e);
    }
}

private static IvParameterSpec calculateIVForOffset(final IvParameterSpec iv,
        final long blockOffset) {
    final BigInteger ivBI = new BigInteger(1, iv.getIV());
    final BigInteger ivForOffsetBI = ivBI.add(BigInteger.valueOf(blockOffset
            / AES_BLOCK_SIZE));

    final byte[] ivForOffsetBA = ivForOffsetBI.toByteArray();
    final IvParameterSpec ivForOffset;
    if (ivForOffsetBA.length >= AES_BLOCK_SIZE) {
        ivForOffset = new IvParameterSpec(ivForOffsetBA, ivForOffsetBA.length - AES_BLOCK_SIZE,
                AES_BLOCK_SIZE);
    } else {
        final byte[] ivForOffsetBASized = new byte[AES_BLOCK_SIZE];
        System.arraycopy(ivForOffsetBA, 0, ivForOffsetBASized, AES_BLOCK_SIZE
                - ivForOffsetBA.length, ivForOffsetBA.length);
        ivForOffset = new IvParameterSpec(ivForOffsetBASized);
    }

    return ivForOffset;
}

这篇关于在android中使用AES CTR模式随机访问InputStream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆