- edited description
RSADecrypter with Android keystore private key
RSADecrypter with Android keystore private key
I'm developing an Android app (on Android 5.1) using Nimbus JWE to communicate with our server. It works fine in prototype using key files from file system. But once we migrated it to use Android keystore, RSADecrypter fails to work anymore. It always throw "com.nimbusds.jose.JOSEException: private exponent cannot be extracted" when trying to call the decrypt function with the private key from the keystore.
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
PrivateKey privateKey = (PrivateKey) ks.getKey(KS_ALIAS,null);
decrypter = new RSADecrypter(privateKey);
jweObject.decrypt(decrypter);
W/System.err: com.nimbusds.jose.JOSEException: private exponent cannot be extracted
W/System.err: at com.nimbusds.jose.crypto.RSA_OAEP_256.decryptCEK(RSA_OAEP_256.java:119)
W/System.err: at com.nimbusds.jose.crypto.RSADecrypter.decrypt(RSADecrypter.java:242)
W/System.err: at com.nimbusds.jose.JWEObject.decrypt(JWEObject.java:415)
W/System.err: at com.gzplanet.xposed.myapplication.MainActivity.decodeJWT(MainActivity.java:383)
W/System.err: at com.gzplanet.xposed.myapplication.MainActivity$5.onClick(MainActivity.java:124)
W/System.err: at android.view.View.performClick(View.java:4780)
W/System.err: at android.view.View$PerformClick.run(View.java:19866)
W/System.err: at android.os.Handler.handleCallback(Handler.java:739)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err: at android.os.Looper.loop(Looper.java:135)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5254)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
W/System.err: at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
W/System.err: Caused by: java.lang.UnsupportedOperationException: private exponent cannot be extracted
W/System.err: at com.android.org.conscrypt.OpenSSLRSAPrivateKey.getPrivateExponent(OpenSSLRSAPrivateKey.java:161)
W/System.err: at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.RSAUtil.generatePrivateKeyParameter(RSAUtil.java:63)
W/System.err: at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineInit(CipherSpi.java:271)
W/System.err: at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineInit(CipherSpi.java:368)
W/System.err: at javax.crypto.Cipher.init(Cipher.java:842)
W/System.err: at javax.crypto.Cipher.init(Cipher.java:793)
W/System.err: at com.nimbusds.jose.crypto.RSA_OAEP_256.decryptCEK(RSA_OAEP_256.java:110)
W/System.err: ... 14 more
Comments (6)
-
reporter -
You will need to configured the decrypter with the same crypto provider as the one for the KeyStore:
decrypter = new RSADecrypter(privateKey); decrypter.getJCAContext().setKeyEncryptionProvider(provider);
-
decrypter.getJCAContext().setKeyEncryptionProvider(ks.getProvider());
-
reporter - changed status to resolved
It turns out AndroidOpenSSL doesn't support RSA_OAEP_256. So when RSA_OAEP_256 is used, Android selects BouncyCastle as the provider which is not allowed to use the keystore private key. When I use RSA1_5 (which is supported by AndroidOpenSSL), the payload is encrypted and signed successfully.
-
Using RSA_OAEP_256 and setting
decrypter.jcaContext.keyEncryptionProvider = keyStore.provider
throws
com.nimbusds.jose.JOSEException: no such algorithm: OAEP for provider AndroidKeyStore
And using RSA1_5 throws
com.nimbusds.jose.JOSEException: MAC check failed
-
Hi @Vladimir Dzhuvinov and others,
This issue was marked as resolved almost two years ago; yet it seems impossible to use the Android KeyStore together with Nimbus JOSE? I have the same errors as Omar above.
If I set the encryption provider as per Vladimir’s earlier comment, I get “No such algorithm: OAEP for provider AndroidKeyStore”.
If I remove that line, I get a bit further, because `Cipher.getInstance()` doesn’t work on Android if the provider is passed (!), but get stuck on that Android only supports SHA-1 for MGF1, and nimbus-jose uses SHA-256.
The only workaround I’ve found so far is to create my own custom sub-class of `RSAEncrypter` and `RSADecrypter` to override `encrypt()` / `decrypt()`, respectively, to use SHA-1 instead of SHA-256, which is not a very pretty solution.
Are there any plans on getting this to work on Android out of the box? Alternatively, some refactoring of the static bindings to the algorithms inside `RSAEncrypter` and `RSADecrypter` would be nice (even extracting a `protected encryptCEK(…)` or even better `protected getCekCipher()` would simplify overriding the cipher parameters, so that custom algorithms could be more easily introduced by clients?
- Log in to comment