1

I'm trying to use a Signature object for signing AND verifying data using fingerprint authentication. It works fine for signing, but when it comes to verifying I get this error :

java.lang.IllegalArgumentException: Crypto primitive not backed by AndroidKeyStore provider: Signature object: SHA256withECDSA, spi: com.android.org.conscrypt.OpenSSLSignature$SHA256ECDSA@cf4a416

The exception is thrown not while generating the key (this part is fine) but when calling fingerprintManager.authenticate(cryptoObject, ...)

Basically this is how I generate a CryptoObject instance :

KeyPairGenerator signatureKeyGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
signatureKeyGenerator.initialize(new KeyGenParameterSpec.Builder(keyName, KeyProperties.PURPOSE_SIGN)
        .setDigests(KeyProperties.DIGEST_SHA256)
        .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
        .setUserAuthenticationRequired(true)
        .build());

KeyPair signatureKey = signatureKeyGenerator.generateKeyPair();

Signature signature = Signature.getInstance("SHA256withECDSA");

switch (MODE) {
    case KeyProperties.PURPOSE_SIGN:
        signature.initSign(signatureKey.getPrivate());
        break;
    case KeyProperties.PURPOSE_VERIFY:
        KeyFactory factory = KeyFactory.getInstance(signatureKey.getPublic().getAlgorithm());
        X509EncodedKeySpec spec = new X509EncodedKeySpec(signatureKey.getPublic().getEncoded());
        PublicKey unrestrictedPublicKey = factory.generatePublic(spec);
        signature.initVerify(unrestrictedPublicKey);
        break;
}

CryptoObject cryptoObject new CryptoObject(signature);

I tried to add | KeyProperties.PURPOSE_VERIFY to KeyGenParameterSpec.Builder but it didn't work either and anyway that's how they do it in the official Google repo : https://github.com/googlesamples/android-AsymmetricFingerprintDialog (weird...)

Finally I tried to look into Android source code to see why the exception is thrown : AndroidKeyStoreProvider.java

Object spi = ((Signature) cryptoPrimitive).getCurrentSpi();
if (spi == null) {
    throw new IllegalStateException("Crypto primitive not initialized");
} else if (!(spi instanceof KeyStoreCryptoOperation)) {
    throw new IllegalArgumentException(
            "Crypto primitive not backed by AndroidKeyStore provider: " + cryptoPrimitive
            + ", spi: " + spi);
}

But I can't even find the getCurrentSpi() method...

Any help would be greatly appreciated !

Community
  • 1
  • 1
Omar Aflak
  • 2,918
  • 21
  • 39

1 Answers1

2

In verification mode, you're initializing the Signature instance using a public key which is not an Android Keystore key. Your issue is similar to Initializing FingerpringManager.Crypto Object, getting Crypto primitive not backed by AndroidKeyStore provider?

Verify a digital signature is not a restrictive operation because is perfomed with the public key, so you really would not need the FingerprintManager and the CryptoObject

Therefore you can use directly

   signature.verify(sigToVerify)` 

or initialize the Signature object with Android Keystore public key

  signature.initVerify(signatureKey.getPublic())
pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • I see ! I didn't understand the first time when I read the other post ! – Omar Aflak Jul 12 '17 at 14:19
  • I'm going to skip the authentication for verifying. But anyway using `signature.initVerify(signatureKey.getPublic())` does not work. I get the same error message. – Omar Aflak Jul 12 '17 at 14:20
  • Ok, in this case the public key is really the one backed into Android Keystore so i guess that the implementation of the verification with the public key can not be performed in the protected zone. As I say above it does not make sense – pedrofb Jul 12 '17 at 14:28