首页 > 解决方案 > 使用 SHA-256 进行主要和 MGF1 摘要的 OAEP 的 Android RSA 加密

问题描述

根据规范,我需要对两个摘要使用带有 SHA-256 的“RSA/ECB/OAEPPadding”密码 - 主摘要和 MGF1 摘要。

Android Cryptography建议Cipher像这样初始化:cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT)); 实际上这不起作用,因为init(DECRYPT_MODE, ...)throws exception: 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;
}

标签: javaandroidencryptioncryptographyrsa

解决方案


推荐阅读