- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有点被这个异常(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());
}
但是,看起来有两个修复方向:
你怎么看?
最佳答案
看起来 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):
BC 1.5(BouncyCaSTLe 安全提供程序 v1.50)
BC 1.52(BouncyCaSTLe 安全提供程序 v1.52)
但是,“显式”密码改变了一些东西:
c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
BC 1.46(BouncyCaSTLe 安全提供程序 v1.46)
AndroidOpenSSL 1.0(Android 的 OpenSSL 支持的安全提供程序)
AndroidOpenSSL 1.0(Android 的 OpenSSL 支持的安全提供程序)
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/
我正在尝试加密/解密一些文件,我将使用通过 CipherIn/OutputStream 进行管道传输的 FileIn/OutputStream 来读取/写入这些文件。概念相当简单,我已经使用原始字节数
我正在编写一个使用 RSA 密码和 AES 密码的公钥和私钥加密算法的实现。在此方法中,AES key 应该使用 RSA CipherInputStream 解密。 public void loadK
我正在测试 Java 中的文本加密。问题是我在行的开头得到一些奇怪的字符,但我不明白为什么。当我删除加密时,一切都会顺利进行。 复制到 Notepad++ 中时,输出如下所示: Hello dear
我有一个类似的方法。它工作正常,但问题是当我尝试解密填充错误甚至根本未加密的文件时。通常我相信 cipher.doFinal(..) 通常会抛出一些与 IllegalBlockSizeExceptio
我有以下函数来加密文件。我打印了两个文件的结果,一切似乎都正常工作。 加密文件已更改,并且与输入文件的长度相同。 public void encrypt(String password, String
我正在尝试读取一个文件,其中部分数据已加密,部分数据未加密。 每条消息的开头都有一个未加密的 header ,其中包含后续加密消息的字节大小。 我要读的类(class)刚刚延长FileInputStr
我正在使用以下代码来解密从 Android 设备加密的文件。 private void mDecrypt_File(FileInputStream fin, String outFile) throw
有没有人知道如何在不将解密文件重写为原始文件的情况下读取解密文件? 下载文件后,文件自动加密。当我想打开文件时,文件会先被解密,但问题是如何从 CipherInputStream 读取文件,这样就不需
我遇到了麻烦,因为我需要关闭 de CIS(否则我不会得到最后 16 个字节),但我不能,因为我通过套接字使用它: cis = new CipherInputStream(new ObjectInpu
我遇到了需要缓冲 CipherInputStream 的场景。确切地说,在将结果返回给 InputStream.read(byte[], int, int) 的调用者之前,我需要确保缓冲区已填充到 3
这个问题已经有答案了: Initial bytes incorrect after Java AES/CBC decryption (10 个回答) 已关闭 4 年前。 我在将 FileInputSt
我有以下代码。但是,文件 b.xlsx 和 c.xlsx 的大小为 0 字节。为什么CipherOuputSteam不工作? public static void main(String[] args
我加密,然后解密一个图像,然后将其传递给我的图像 util 以调整大小,(从某处慷慨地借用代码)像这样: public static Bitmap loadResizedBitmap(InputStr
我有点被这个异常(exception)困住了: java.lang.RuntimeException: error:0407806d:RSA routines:decrypt:DATA_LEN_NOT
我遇到了一个问题,如果使用 CipherInputStream,则针对 FileInputStream 支持的 InputStream 的代码不起作用。 示例如下: // skipCount is
我想将一个加密流添加到我的多方实体中,以将其上传到我的 servlet,但我不知道该怎么做... 嗯,那么 MultipartEntity 对于 addPart(...,...) 来说是相当有限的方法
我的文件包含开头包含未加密的 header 数据,然后其余部分包含加密的 header 数据。我希望能够使用 BufferedInputStream/FileInputSteam 读取 header
我一直在尝试用 AES 编写一个加密文件,然后使用 JCA 中提供的密码流对其进行解密。但是,我在读取文件时遇到了问题,因为解密正在失控。 public class CipherStreams { p
我一直在研究 Java 中的加密,并且遇到了奇怪的行为。使用 加密 byte[] 数据时 InputStream fin = new ByteArrayInputStream(data); Ciphe
我正在编写基于客户端-服务器的 Java 应用程序,但遇到了一个问题,因为在客户端和服务器中构造 ObjectInputStream 时它会挂起。 客户: Socket socket = new So
我是一名优秀的程序员,十分优秀!