By specification I need to use "RSA/ECB/OAEPPadding" cipher with SHA-256 for both digests - the main digest and the MGF1 digest.
Android Cryptography suggests to initialize Cipher like this: cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
In reality this is not working, because init(DECRYPT_MODE, ...) throws exception: InvalidAlgorithmParameterException, Unsupported MGF1 digest: SHA-256. Only SHA-1 supported.
Do anyone know, how to resolve this problem? Using another algorithm parameters in no option.
This is the code sample, run encryptDecrypt() to reproduce the error. Minimum api level is 23.
static void encryptDecrypt()
{
KeyPair keyPair = generateWrappingKeypair("MY_KEY");
try
{
Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] data = new byte[1]; // Just create the smallest data to encrypt
// Encryption goes well
byte[] encrypted = cipher.doFinal(new byte[1]);
// This line throws exception: "InvalidAlgorithmParameterException, Unsupported MGF1 digest: SHA-256. Only SHA-1 supported"
cipher = getCipher(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] decrypted = cipher.doFinal(encrypted);
if (!Arrays.equals(data, decrypted))
{
throw new RuntimeException("Decrypted data is not equals to raw data");
}
}
catch (Exception ex)
{
Log.e(TAG, "Encryption error, exception: " + ex.getClass().getSimpleName() + " " + ex.getMessage());
}
}
static KeyPair generateWrappingKeypair(String aliasOfKey)
{
Calendar dateValidFrom = Calendar.getInstance();
Calendar dateValidTo = Calendar.getInstance();
dateValidTo.add(Calendar.YEAR, 1);
KeyGenParameterSpec specOfKey = new KeyGenParameterSpec.Builder(aliasOfKey, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F0))
.setKeySize(4096)
.setKeyValidityStart(dateValidFrom.getTime())
.setKeyValidityEnd(dateValidTo.getTime())
.setCertificateSerialNumber(BigInteger.ONE)
.setCertificateSubject(new X500Principal(String.format("CN=%s", aliasOfKey)))
.setDigests(KeyProperties.DIGEST_SHA256) // Setting two SHA256 digests here don't make any difference
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.build();
try
{
KeyPairGenerator generatorOfKeyPairs = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
generatorOfKeyPairs.initialize(specOfKey);
return generatorOfKeyPairs.generateKeyPair();
}
catch (GeneralSecurityException ex)
{
Log.e(TAG, "Cannot generate keypair, exception: " + ex.getClass().getSimpleName() + " " + ex.getMessage());
return null;
}
}
static Cipher getCipher(int operationMode, Key key) throws GeneralSecurityException
{
// AndroidKeyStoreBCWorkaround should be used here from API 23 for Cipher to be compatible with AndroidKeyStore keys
// Any other security provider is not compatible
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding", "AndroidKeyStoreBCWorkaround");
cipher.init(operationMode, key, new OAEPParameterSpec(KeyProperties.DIGEST_SHA256, "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
return cipher;
}