发布于2021-11-23 09:18 阅读(1217) 评论(0) 点赞(19) 收藏(0)
我正在尝试在 Android 上使用 javax.crypto.Cipher 来使用 AES-GCM 以块的形式加密数据流。据我了解,可以多次使用 Cipher.update 进行多部分加密操作,并使用 Cipher.doFinal 完成。但是,当使用 AES/GCM/NoPadding 转换时,Cipher.update 拒绝将数据输出到提供的缓冲区,并返回写入的 0 字节。缓冲区在密码内部建立,直到我调用 .doFinal。这似乎也发生在 CCM(我假设其他经过身份验证的模式)中,但适用于其他模式,如 CBC。
我认为 GCM 可以在加密时计算身份验证标签,所以我不确定为什么我不允许使用密码中的缓冲区。
我做了一个例子,只调用了一次 .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
我想要做的是从磁盘流式传输一个大文件,对其进行加密并通过网络块一个块地发送它,而不必将整个文件数据加载到内存中。我尝试使用 CipherInputStream 但它遇到了同样的问题。
这可能与 AES/GCM 一起使用吗?
这是由 Android 现在默认使用的 Conscrypt 提供程序的限制引起的。这是我运行的不是Android 而是我的 Mac 上显式使用 Conscrypt 提供程序的代码示例,接下来使用 Bouncycastle (BC) 提供程序来显示差异。因此,解决方法是将 BC 提供程序添加到您的 Android 项目中,并在调用Cipher.getInstance()
. 当然,有一个权衡。虽然 BC 提供者会在每次调用时向您返回密文,update()
但总体吞吐量可能会大大降低,因为 Conscrypt 使用本机库,而 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);
}
}
}
作者:黑洞官方问答小能手
链接:http://www.javaheidong.com/blog/article/329928/b3f87a73409f7b1d969c/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!