Android KeyStore private exponent cannot be extrac

2020-05-27 02:27发布

问题:

I want to generate a RSA keypair in the Android Keystore. Since Android 4.3 is should be possible to generate RSA keys in the Android system Keystore.

I generate my RSA key by (works fine)

        Calendar notBefore = Calendar.getInstance();
        Calendar notAfter = Calendar.getInstance();
        notAfter.add(1, Calendar.YEAR);
        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(ctx)
                .setAlias("key")
                .setSubject(
                        new X500Principal(String.format("CN=%s, OU=%s",
                                "key", ctx.getPackageName())))
                .setSerialNumber(BigInteger.ONE)
                .setStartDate(notBefore.getTime())
                .setEndDate(notAfter.getTime()).build();
            KeyPairGenerator kpg;
            kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
            kpg.initialize(spec);
            KeyPair kp = kpg.genKeyPair();
            publicKey = kp.getPublic();
            privateKey = kp.getPrivate();

my RSA encryption looks like (works also):

    public static byte[] RSAEncrypt(final byte[] plain)
        throws NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

    Cipher cipher = Cipher.getInstance("RSA");
    System.out.println("RSA Encryption key: " + publicKey.getAlgorithm());
    System.out.println("RSA Encryption key: " + publicKey.getEncoded());

    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] encryptedBytes = cipher.doFinal(plain);
    return encryptedBytes;
}

decryption:

    public static byte[] RSADecrypt(final byte[] encryptedBytes)
        throws NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

    Cipher cipher1 = Cipher.getInstance("RSA");

    System.out.println("RSA Encryption key: " + privateKey.getAlgorithm());
    System.out.println("RSA Encryption key: " + privateKey.getEncoded());

    cipher1.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] decryptedBytes = cipher1.doFinal(encryptedBytes);
    return decryptedBytes;
}

In the decryption function i get the following error message(when the privateKey is encoded, and in cipher1.init()):

12-12 21:49:40.338: E/AndroidRuntime(20423): FATAL EXCEPTION: main
12-12 21:49:40.338: E/AndroidRuntime(20423): java.lang.UnsupportedOperationException: private    exponent cannot be extracted
12-12 21:49:40.338: E/AndroidRuntime(20423):    at org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey.getPrivateExponent(OpenSSLRSAPrivateKey.java:143)

I don't get it. Is it not possible to generate a RSA key in the Android KeyStore? Can anyone provide me with an example of generating a RSA key in the Android KeyStore and decrypt with the private Key.

Many Thanks in advance!

回答1:

According to the code, I think that the OpenSSL provider prevents the private exponent to be exported when the key has been generated into the device.

@Override
public final BigInteger getPrivateExponent() {
    if (key.isEngineBased()) {
        throw new UnsupportedOperationException("private exponent cannot be extracted");
    }

    ensureReadParams();
    return privateExponent;
}

Thus, you probably need to specify that you want to use the same crypto provider when retrieving the cipher instance. This provider supports these RSA ciphers:

  • RSA/ECB/NoPadding
  • RSA/ECB/PKCS1Padding

You should create an instance of the cipher this way:

Cipher cipher1 = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");