gpt4 book ai didi

使用 AES/GCM (Android 9) 时,Java Cipher.update 不写入缓冲区

转载 作者:搜寻专家 更新时间:2023-11-01 09:19:38 25 4
gpt4 key购买 nike

我正在尝试在 Android 上使用 javax.crypto.Cipher 来使用 AES-GCM 以 block 的形式加密数据流。据我了解,可以多次使用 Cipher.update 进行多部分加密操作,并使用 Cipher.doFinal 完成。但是,当使用 AES/GCM/NoPadding 转换时,Cipher.update 拒绝将数据输出到提供的缓冲区,并返回写入的 0 个字节。在我调用 .doFinal 之前,缓冲区会在 Cipher 内部累积。这似乎也发生在 CCM 中(我假设其他经过身份验证的模式),但适用于 CBC 等其他模式。

我认为 GCM 可以在加密时计算身份验证标签,所以我不确定为什么不允许我使用 Cipher 中的缓冲区。

我做了一个例子,只调用了一次 .update: (kotlin)

val secretKey = KeyGenerator.getInstance("AES").run {
init(256)
generateKey()
}

val iv = ByteArray(12)
SecureRandom().nextBytes(iv)

val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(iv))

// Pretend this is some file I want to read and encrypt
val inputBuffer = Random.nextBytes(1024000)

val outputBuffer = ByteArray(cipher.getOutputSize(512))

val read = cipher.update(inputBuffer, 0, 512, outputBuffer, 0)
// ^ at this point, read = 0 and outputBuffer is [0, 0, 0, ...]
// Future calls to cipher.update and cipher.getOutputSize indicate that
// the internal buffer is growing. But I would like to consume it through
// outputBuffer

// ...

cipher.doFinal(outputBuffer, 0)
// Now outputBuffer is populated

我想做的是从磁盘流式传输一个大文件,对其进行加密并通过网络逐 block 发送,而不必将整个文件数据加载到内存中。我曾尝试使用 CipherInputStream,但它遇到了同样的问题。

AES/GCM 是否可行?

最佳答案

这是由 Android 现在默认使用的 Conscrypt 提供程序的限制引起的。下面是一个代码示例,我不是在 Android 上运行,而是在我的 Mac 上运行,它明确使用 Conscrypt 提供程序,接下来使用 BouncycaSTLe (BC) 提供程序来显示差异。因此,解决方法是将 BC 提供程序添加到您的 Android 项目,并在调用 Cipher.getInstance() 时明确指定它。当然,需要权衡取舍。虽然 BC 提供程序会在每次调用 update() 时向您返回密文,但总体吞吐量可能会大大降低,因为 Conscrypt 使用 native 库并且 BC 是纯 Java。

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.conscrypt.Conscrypt;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;

public class ConscryptIssue1 {

private final static Provider CONSCRYPT = Conscrypt.newProvider();
private final static Provider BC = new BouncyCastleProvider();

public static void main(String[] args) throws GeneralSecurityException {
Security.addProvider(CONSCRYPT);
doExample();
}

private static void doExample() throws GeneralSecurityException {
final SecureRandom secureRandom = new SecureRandom();
{
// first, try with Conscrypt
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256, secureRandom);
SecretKey aesKey = keyGenerator.generateKey();
byte[] plaintext = new byte[10000]; // plaintext is all zeros
byte[] nonce = new byte[12];
secureRandom.nextBytes(nonce);
Cipher c = Cipher.getInstance("AES/GCM/NoPadding", CONSCRYPT);// specify the provider explicitly
GCMParameterSpec spec = new GCMParameterSpec(128, nonce);// tag length is specified in bits.
c.init(Cipher.ENCRYPT_MODE, aesKey, spec);
byte[] outBuf = new byte[c.getOutputSize(512)];
int numProduced = c.update(plaintext, 0, 512, outBuf, 0);
System.out.println(numProduced);
final int finalProduced = c.doFinal(outBuf, numProduced);
System.out.println(finalProduced);
}

{
// Next, try with Bouncycastle
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256, secureRandom);
SecretKey aesKey = keyGenerator.generateKey();
byte[] plaintext = new byte[10000]; // plaintext is all zeros
byte[] nonce = new byte[12];
secureRandom.nextBytes(nonce);
Cipher c = Cipher.getInstance("AES/GCM/NoPadding", BC);// specify the provider explicitly
GCMParameterSpec spec = new GCMParameterSpec(128, nonce);// tag length is specified in bits.
c.init(Cipher.ENCRYPT_MODE, aesKey, spec);
byte[] outBuf = new byte[c.getOutputSize(512)];
int numProduced = c.update(plaintext, 0, 512, outBuf, 0);
System.out.println(numProduced);
final int finalProduced = c.doFinal(outBuf, numProduced);
System.out.println(finalProduced);
}

}
}

关于使用 AES/GCM (Android 9) 时,Java Cipher.update 不写入缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57382238/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com