Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spongy Castle RSA Encryption/Decryption with Android Keystore

Attempting to use SpongyCastle to provide the preferred encryption algorithm of RSA/ECB/OAEPwithSHA-512andMGF1Padding for Asymmetric encryption/decryption tasks on all supported Android device versions and having issues.

Encryption appears to be working fine. But decryption is proving some trouble:

No provider for RSA/ECB/OAEPwithSHA-512andMGF1Padding

KeyGen spec is as follows:

val generatorSpec = KeyPairGeneratorSpec.Builder(context)
            .setAlias(ALIAS)
            .setSubject(X500Principal(ASYMMETRIC_KEY_COMMON_NAME_PREFIX + ALIAS))
            .setSerialNumber(BigInteger.TEN)
            .setStartDate(creationDate.time)
            .setEndDate(expiryDate.time)
            .build()

val keyPairGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore")
keyPairGenerator.initialize(generatorSpec)

keyPairGenerator.generateKeyPair()

I'm now grabbing this value from the keyStore and trying to use it for decryption/encryption:

private fun rsaEncrypt(data: ByteArray, key: KeyStore.PrivateKeyEntry): ByteArray {
    val encryptionCipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-512andMGF1Padding", "SC")
    encryptionCipher.init(Cipher.ENCRYPT_MODE, key.certificate.publicKey)

    val outputStream = ByteArrayOutputStream()

    val cipherOutputStream = CipherOutputStream(outputStream as OutputStream, encryptionCipher)
    cipherOutputStream.write(data)
    cipherOutputStream.close()

    return outputStream.toByteArray()
}

This appears to work fine, however decryption is where my issue lies:

private fun rsaDecrypt(data: ByteArray, key: KeyStore.PrivateKeyEntry): ByteArray {
    val decryptionCipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-512andMGF1Padding", "SC")
    decryptionCipher.init(Cipher.DECRYPT_MODE, key.privateKey)

   // Rest of code for cipher streaming etc. etc.
}

initialising the decryptionCipher is giving me:

java.security.ProviderException: No provider for RSA/ECB/OAEPwithSHA-512andMGF1Padding

Which is strange due to my cipher instance returning fine and encryption working fine.

Also tried specifying the provider as “BC” rather than “SC” which gives a private exponent cannot be extracted error which I’m thinking is by design. Trying to give a algorithm that isn't supported will break on the cipher initialisation and Encryption via Provider SC doesn't provide xxx so what gives?

TLDR: The encryption cipher has the same provider as decryption. But only decryption breaks.... There has to be something I’m missing here but can’t seem to put my finger on it. I've been working on this a while so any help is appreciated!

Edit: For interest I'm providing SpongyCastle through:

init { 
    Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME)
    Security.addProvider(BouncyCastleProvider())
    keyStore.load(null)
}
like image 470
Mark Bergin Avatar asked Feb 23 '18 00:02

Mark Bergin


1 Answers

You can not decrypt with BC/SC using a key managed by AndroidKeyStore because the private key content is protected and its parameters (such as private exponent) are hidden, so any attempt to initialize a cipher with that key will fail.

The error message No provider for RSA/ECB/OAEPwithSHA-512andMGF1Padding using SC is probably due to an incorrect error handling by the library, but the private exponent cannot be extracted error for BC is clear. Encryption works because it uses the public key, which is not protected.

You need to use AndroidKeyStore for decryption (or use SC/BC also to generate the keys).

like image 169
pedrofb Avatar answered Nov 08 '22 19:11

pedrofb