Hi @esamelson, the issue appears when you want to use the hardware backed keystore, AndroidKeyStore. The following example illustrates the problem:
// register BouncyCastle/SpongyCastle
Security.insertProviderAt(new BouncyCastleProvider(), 1);
// generate a EC secp256r1 key pair using the AndroidKeyStore
KeyPairGenerator generator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
AlgorithmParameterSpec spec = new KeyGenParameterSpec.Builder(
"test-" + System.currentTimeMillis(),
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512, KeyProperties.DIGEST_NONE)
.build();
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
// prepare test data
byte[] data = new byte[20];
new Random().nextBytes(data);
// try to sign the data
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initSign(keyPair.getPrivate()); // <-- it fails here
sig.update(data);
byte[] signature = sig.sign();
System.out.println("signature is "+Arrays.toString(signature));
This leads to: java.security.InvalidKeyException: cannot identify EC private key: java.security.InvalidKeyException: no encoding for EC private key
One way to work around that issue is to specify the crypto provider like:
Signature sig = Signature.getInstance("SHA256withECDSA", "AndroidKeyStoreBCWorkaround");
Unfortunately, this provider is - as fas as I researched - not documented. It’s in the compatibility document for Android 9 but may be subject to change in future versions. Also, the problem remains for Android < 6.0 because this provider does not exist there.
The current workaround we have in place moves the SC provider to the last position in provider list before initializing Signature and put it back in place afterwards, hoping there’s no parallel execution which requires SC during that.