gpt4 book ai didi

android - 关闭 CipherInputStream 时出现 RuntimeException

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

我有点被这个异常(exception)困住了:

java.lang.RuntimeException: error:0407806d:RSA routines:decrypt:DATA_LEN_NOT_EQUAL_TO_MOD_LEN
at com.android.org.conscrypt.NativeCrypto.RSA_private_decrypt(Native Method)
at com.android.org.conscrypt.OpenSSLCipherRSA.engineDoFinal(OpenSSLCipherRSA.java:274)
at javax.crypto.Cipher.doFinal(Cipher.java:1440)
at javax.crypto.CipherInputStream.close(CipherInputStream.java:190)
...

当我在 Android Marshmallow 上关闭 CipherInputStream 时抛出。一切似乎都适用于早期的 Android 版本。

DATA_LEN_NOT_EQUAL_TO_MOD_LEN 是什么意思?为什么它似乎在应该释放资源句柄(关闭)时解密(调用 RSA_private_decrypt)?

更新:

我设法用一些测试代码重现了这个错误。它加密和解密“foobar”。一次直接使用密码,一次通过 CipherInputStream(就像在原始应用程序中完成的那样)。

一切都适用于 android < 6,非流式代码甚至适用于 android 6。当我将显式密码 RSA/ECB/PKCS1Padding 更改为通用 RSA 时,我能够让流代码在 android 6 上工作。但我敢打赌,它的存在是有原因的;)

static final String RSA_ALGO = "RSA/ECB/PKCS1Padding";
// static final String RSA_ALGO = "RSA";

private void _testCrypto2() throws Exception {
KeyPairGenerator keyGen;
KeyPair keys;
byte[] encrypted;
byte[] decrypted;
String input;
String output;

keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
keys = keyGen.generateKeyPair();

input = "foobar";

// Plain crypto.
encrypted = this.RSAEncrypt(input, keys.getPublic());
output = this.RSADecrypt(encrypted, keys.getPrivate());

// Streaming crypto.
encrypted = this.RSAEncryptStream(input, keys.getPublic());
output = this.RSADecryptStream(encrypted, keys.getPrivate());
}

public byte[] RSAEncrypt(final String plain, PublicKey _publicKey) throws Exception {
byte[] encryptedBytes;
Cipher cipher;

cipher = Cipher.getInstance(RSA_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, _publicKey);
encryptedBytes = cipher.doFinal(plain.getBytes());

return encryptedBytes;
}

public String RSADecrypt(final byte[] encryptedBytes, PrivateKey _privateKey) throws Exception {
Cipher cipher;
byte[] decryptedBytes;
String decrypted;

cipher = Cipher.getInstance(RSA_ALGO);
cipher.init(Cipher.DECRYPT_MODE, _privateKey);

decryptedBytes = cipher.doFinal(encryptedBytes);
decrypted = new String(decryptedBytes);

return decrypted;
}

public byte[] RSAEncryptStream(final String _plain, PublicKey _publicKey) throws Exception {
Cipher cipher;
InputStream in;
ByteArrayOutputStream out;
int numBytes;
byte buffer[] = new byte[0xffff];

in = new ByteArrayInputStream(_plain.getBytes());
out = new ByteArrayOutputStream();
cipher = Cipher.getInstance(RSA_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, _publicKey);

try {
in = new CipherInputStream(in, cipher);
while ((numBytes = in.read(buffer)) != -1) {
out.write(buffer, 0, numBytes);
}
}
finally {
in.close();
}

return out.toByteArray();
}

public String RSADecryptStream(final byte[] _encryptedBytes, PrivateKey _privateKey) throws Exception {
Cipher cipher;
InputStream in;
ByteArrayOutputStream out;
int numBytes;
byte buffer[] = new byte[0xffff];

in = new ByteArrayInputStream(_encryptedBytes);
out = new ByteArrayOutputStream();
cipher = Cipher.getInstance(RSA_ALGO);
cipher.init(Cipher.DECRYPT_MODE, _privateKey);

try {
in = new CipherInputStream(in, cipher);
while ((numBytes = in.read(buffer)) != -1) {
out.write(buffer, 0, numBytes);
}
}
finally {
in.close();
}

return new String(out.toByteArray());
}

但是,看起来有两个修复方向:

  • 摆脱 RSA 的流式传输
  • 删除显式 RSA 密码实例化

你怎么看?

最佳答案

看起来 android 的默认安全提供程序有一些变化。

Cipher        c;
Provider p;
StringBuilder bldr;

c = Cipher.getInstance("RSA");
p = cipher.getProvider();
bldr = new StringBuilder();

bldr.append(_p.getName())
.append(" ").append(_p.getVersion())
.append(" (").append(_p.getInfo()).append(")");
Log.i("test", bldr.toString());

它似乎在所有测试的 Android 版本上使用了一个版本的 BouncyCaSTLe(我测试到 2.3):

  • Android 5:BC 1.5(BouncyCaSTLe 安全提供程序 v1.50)
  • Android 6:BC 1.52(BouncyCaSTLe 安全提供程序 v1.52)

但是,“显式”密码改变了一些东西:

c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  • Android 4.1.2:BC 1.46(BouncyCaSTLe 安全提供程序 v1.46)
  • Android 4.4.2:AndroidOpenSSL 1.0(Android 的 OpenSSL 支持的安全提供程序)
  • Android 5.1.1:AndroidOpenSSL 1.0(Android 的 OpenSSL 支持的安全提供程序)
  • Android 6.0.1:AndroidKeyStoreBCWorkaround 1.0(Android KeyStore 安全提供程序解决 Bouncy CaSTLe)

所以最终的解决方案是将提供程序显式设置为 BouncyCaSTLe,它适用于所有经过测试的 android 版本,即使是流式传输也是如此:

Provider p;
Cipher c;

p = Security.getProvider("BC");
c = Cipher.getInstance("RSA/ECB/PKCS1Padding", p);

关于android - 关闭 CipherInputStream 时出现 RuntimeException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35873174/

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