根据规范,我需要对两种摘要(主摘要和MGF1摘要)均使用带有SHA-256的“ RSA / ECB / OAEPPadding”密码。
Android Cryptography建议像这样初始化Cipher
:cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
实际上,这是行不通的,因为init(DECRYPT_MODE, ...)
抛出异常:InvalidAlgorithmParameterException, Unsupported MGF1 digest: SHA-256. Only SHA-1 supported
。
有人知道如何解决此问题吗?不能使用其他算法参数。
这是代码示例,运行encryptDecrypt()
以重现该错误。最低API级别为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;
}