時那種我卡住了與此異常:RuntimeException的收盤CipherInputStream
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棉花糖CipherInputStream它被拋出。一切似乎都適用於早期的Android版本。
DATA_LEN_NOT_EQUAL_TO_MOD_LEN
是什麼意思?爲什麼它應該解密(調用RSA_private_decrypt
)何時應該釋放資源句柄(關閉)?
更新:
我設法用一些測試代碼重現錯誤。它加密和解密"foobar"
。有一次直接使用密碼,一次使用CipherInputStream(就像在原始應用程序中完成的那樣)。
一切工作在Android < 6和非流代碼,即使是在Android 6 工作,我能得到的流碼,即可在Android 6工作時,我改變了明確的密碼RSA/ECB/PKCS1Padding
仿製RSA
。 但我敢打賭,它的存在是有原因的;)
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密碼實例化
您認爲如何?
更重要的是,您爲什麼要將RSA密碼和InputStream一起使用? RSA不適合加密/解密數據流。這個問題可能是支持經過身份驗證的密碼的某種更改。經過驗證的密碼對輸入流並不滿意,恕我直言,使用了一個拙劣的API。從流中讀取數據後,可能需要驗證認證標記和/或填充。這將是一個很好的理由,稱'doFinal' –
@MaartenBodewes謝謝你。它只是一個帶AES加密密鑰的字節流,因此它不是數據量的問題。但暗示可能是正確的。當只有一個「單詞」解密時,沒有用的流。我用一些測試代碼更新答案。 – lupz