IllegalBlockSizeException "null" Android 上的 RSA 解密
IllegalBlockSizeException "null" in RSA decryption on Android
我目前正在使用我的加密软件的 Android 客户端,但我一直收到 IllegalBlockSizeException
,并且 e.getMessage()
总是 returns null
这是我用来查找问题的代码
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA,"AndroidKeyStore");
generator.initialize(new KeyGenParameterSpec.Builder(
"1",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setDigests(KeyProperties.DIGEST_SHA256)
.setKeySize(2048)
.build());
KeyPair kp = generator.generateKeyPair();
KeyStore store = KeyStore.getInstance("AndroidKeyStore");
store.load(null);
PublicKey pubKey = store.getCertificate("1").getPublicKey();
PrivateKey privkey = ((KeyStore.PrivateKeyEntry) store.getEntry("1",null)).getPrivateKey();
byte[] content = "123456789".getBytes();
Cipher encrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
encrypt.init(Cipher.ENCRYPT_MODE,pubKey);
Cipher decrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
decrypt.init(Cipher.DECRYPT_MODE,privkey);
byte[] A = encrypt.doFinal(content);
byte[] B = decrypt.doFinal(A);
String resultA = new String(A);
String resultB = new String(B);
Toast.makeText(getApplicationContext(), resultA + "\n" + resultB, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString()+"\n"+e.getMessage(), Toast.LENGTH_LONG).show();
}
正如我所说,有一个 IllegalBlockSizeException
,我发现它是由 decrypt.doFinal()
和 e.getMessage()
returns null
抛出的
这是我从调试控制台得到的结果
W/System.err: javax.crypto.IllegalBlockSizeException
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:519)
at javax.crypto.Cipher.doFinal(Cipher.java:1741)
W/System.err: at storm.cyanine.decryptor.MainActivity$override.onJob(MainActivity.java:187)
at storm.cyanine.decryptor.MainActivity$override.onOpen(MainActivity.java:115)
at storm.cyanine.decryptor.MainActivity$override.access$dispatch(Unknown Source:50)
at storm.cyanine.decryptor.MainActivity.onOpen(Unknown Source:15)
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
W/System.err: at android.view.View.performClick(View.java:6329)
at android.view.View$PerformClick.run(View.java:24996)
at android.os.Handler.handleCallback(Handler.java:809)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7377)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)
W/System.err: Caused by: android.security.KeyStoreException: Unknown error
at android.security.KeyStore.getKeyStoreException(KeyStore.java:709)
at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
... 16 more
起初,我以为是AndroidKeyStore
的一些限制阻止我使用私钥,所以我尝试直接使用KeyPairGenerator
生成的私钥,但没有任何改变
什么可能导致此问题?
我在网上搜索了好几天,没有发现上面的代码有什么问题(除了不是最终产品)
我的设备是 Android 8.1.0
Edit: Thanks Steve Miskovetz a lot for the solution, and I just found the Android official guide for this topic:
Cryptography
(don't know why I wasn't able to find this earlier)
您的问题似乎是由 Android Oreo 引入的,但有解决方法。
这个 Whosebug post 对此进行了讨论:
Android 8.0: IllegalBlocksizeException when using RSA/ECB/OAEPWithSHA-512AndMGF1Padding
这个 Google 问题跟踪器对此有很好的讨论:
https://issuetracker.google.com/issues/36708951
您需要添加这一行:
OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
并修改这些行,添加 sp 参数:
encrypt.init(Cipher.ENCRYPT_MODE,pubKey,sp);
decrypt.init(Cipher.DECRYPT_MODE,privkey,sp);
您在此处进行修改后的完整代码:
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA,"AndroidKeyStore");
generator.initialize(new KeyGenParameterSpec.Builder(
"1",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setDigests(KeyProperties.DIGEST_SHA256)
.setKeySize(2048)
.build());
KeyPair kp = generator.generateKeyPair();
KeyStore store = KeyStore.getInstance("AndroidKeyStore");
store.load(null);
PublicKey pubKey = store.getCertificate("1").getPublicKey();
PrivateKey privkey = ((KeyStore.PrivateKeyEntry) store.getEntry("1",null)).getPrivateKey();
byte[] content = "123456789".getBytes();
OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
Cipher encrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
encrypt.init(Cipher.ENCRYPT_MODE,pubKey,sp);
Cipher decrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
decrypt.init(Cipher.DECRYPT_MODE,privkey,sp);
byte[] A = encrypt.doFinal(content);
byte[] B = decrypt.doFinal(A);
String resultA = new String(A);
String resultB = new String(B);
Toast.makeText(getApplicationContext(), resultA + "\n" + resultB, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString()+"\n"+e.getMessage(), Toast.LENGTH_LONG).show();
}
非对称密钥加密可从 android 6+(api 23+)获得。这是 android 加密的一个很好的指南。在调用 getBytes 之后,您还需要使用 Base64 对字节进行编码。
我目前正在使用我的加密软件的 Android 客户端,但我一直收到 IllegalBlockSizeException
,并且 e.getMessage()
总是 returns null
这是我用来查找问题的代码
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA,"AndroidKeyStore");
generator.initialize(new KeyGenParameterSpec.Builder(
"1",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setDigests(KeyProperties.DIGEST_SHA256)
.setKeySize(2048)
.build());
KeyPair kp = generator.generateKeyPair();
KeyStore store = KeyStore.getInstance("AndroidKeyStore");
store.load(null);
PublicKey pubKey = store.getCertificate("1").getPublicKey();
PrivateKey privkey = ((KeyStore.PrivateKeyEntry) store.getEntry("1",null)).getPrivateKey();
byte[] content = "123456789".getBytes();
Cipher encrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
encrypt.init(Cipher.ENCRYPT_MODE,pubKey);
Cipher decrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
decrypt.init(Cipher.DECRYPT_MODE,privkey);
byte[] A = encrypt.doFinal(content);
byte[] B = decrypt.doFinal(A);
String resultA = new String(A);
String resultB = new String(B);
Toast.makeText(getApplicationContext(), resultA + "\n" + resultB, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString()+"\n"+e.getMessage(), Toast.LENGTH_LONG).show();
}
正如我所说,有一个 IllegalBlockSizeException
,我发现它是由 decrypt.doFinal()
和 e.getMessage()
returns null
这是我从调试控制台得到的结果
W/System.err: javax.crypto.IllegalBlockSizeException
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:519)
at javax.crypto.Cipher.doFinal(Cipher.java:1741)
W/System.err: at storm.cyanine.decryptor.MainActivity$override.onJob(MainActivity.java:187)
at storm.cyanine.decryptor.MainActivity$override.onOpen(MainActivity.java:115)
at storm.cyanine.decryptor.MainActivity$override.access$dispatch(Unknown Source:50)
at storm.cyanine.decryptor.MainActivity.onOpen(Unknown Source:15)
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
W/System.err: at android.view.View.performClick(View.java:6329)
at android.view.View$PerformClick.run(View.java:24996)
at android.os.Handler.handleCallback(Handler.java:809)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7377)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)
W/System.err: Caused by: android.security.KeyStoreException: Unknown error
at android.security.KeyStore.getKeyStoreException(KeyStore.java:709)
at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
... 16 more
起初,我以为是AndroidKeyStore
的一些限制阻止我使用私钥,所以我尝试直接使用KeyPairGenerator
生成的私钥,但没有任何改变
什么可能导致此问题?
我在网上搜索了好几天,没有发现上面的代码有什么问题(除了不是最终产品)
我的设备是 Android 8.1.0
Edit: Thanks Steve Miskovetz a lot for the solution, and I just found the Android official guide for this topic: Cryptography
(don't know why I wasn't able to find this earlier)
您的问题似乎是由 Android Oreo 引入的,但有解决方法。
这个 Whosebug post 对此进行了讨论:
Android 8.0: IllegalBlocksizeException when using RSA/ECB/OAEPWithSHA-512AndMGF1Padding
这个 Google 问题跟踪器对此有很好的讨论:
https://issuetracker.google.com/issues/36708951
您需要添加这一行:
OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
并修改这些行,添加 sp 参数:
encrypt.init(Cipher.ENCRYPT_MODE,pubKey,sp);
decrypt.init(Cipher.DECRYPT_MODE,privkey,sp);
您在此处进行修改后的完整代码:
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA,"AndroidKeyStore");
generator.initialize(new KeyGenParameterSpec.Builder(
"1",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setDigests(KeyProperties.DIGEST_SHA256)
.setKeySize(2048)
.build());
KeyPair kp = generator.generateKeyPair();
KeyStore store = KeyStore.getInstance("AndroidKeyStore");
store.load(null);
PublicKey pubKey = store.getCertificate("1").getPublicKey();
PrivateKey privkey = ((KeyStore.PrivateKeyEntry) store.getEntry("1",null)).getPrivateKey();
byte[] content = "123456789".getBytes();
OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
Cipher encrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
encrypt.init(Cipher.ENCRYPT_MODE,pubKey,sp);
Cipher decrypt = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
decrypt.init(Cipher.DECRYPT_MODE,privkey,sp);
byte[] A = encrypt.doFinal(content);
byte[] B = decrypt.doFinal(A);
String resultA = new String(A);
String resultB = new String(B);
Toast.makeText(getApplicationContext(), resultA + "\n" + resultB, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString()+"\n"+e.getMessage(), Toast.LENGTH_LONG).show();
}
非对称密钥加密可从 android 6+(api 23+)获得。这是 android 加密的一个很好的指南。在调用 getBytes 之后,您还需要使用 Base64 对字节进行编码。