在android中使用AES CTR模式随机访问InputStream

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

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

我正在尝试解密存储在Android中的SD卡上的加密video文件。 嵌入式HTTP文件服务器即时解密它。 一切正常,直到用户在video中执行搜索:video立即停止,因为它接收到损坏的video流。

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

  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); 

您不应该使用流来实现它。 流用于顺序访问数据。 跳过仅应用于向前跳短距离并标记/重置仅用于向后跳跃小距离。

使用文件映射可能是最有效的。 对于稍微简单的方法但效率较​​低的方法,您可以使用RandomAccessFile 。 此外,您应该使用“IV”来使用Cipher.getInstance("AES/CTR/NoPadding") ,该“IV”设置为您在文件中开始的位置所期望的计数器。


使用带偏移的CTR的示例代码:

 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; }