1

I have a mobile application which has Finger Print Authentication and it uses xamarin framework. Until now everything worked well with all devices except Samsung Note 8. While trying to debug this device it gives me an exception Java.Lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(). I have no idea what does it mean and how to fix it because it works well with other devices. It gives exception on row keyGen.Init(keyGenSpec)

    static readonly string KEY_NAME = "YYYYYYY";

    static readonly string KEYSTORE_NAME = "AndroidKeyStore";

    static readonly string KEY_ALGORITHM = KeyProperties.KeyAlgorithmAes;
    static readonly string BLOCK_MODE = KeyProperties.BlockModeCbc;
    static readonly string ENCRYPTION_PADDING = KeyProperties.EncryptionPaddingPkcs7;

    static readonly string TRANSFORMATION = KEY_ALGORITHM + "/" +
                                            BLOCK_MODE + "/" +
                                            ENCRYPTION_PADDING;

    readonly KeyStore _keystore;

    public CryptoObjectHelper()
    {
        _keystore = KeyStore.GetInstance(KEYSTORE_NAME);
        _keystore.Load(null);
    }

    public FingerprintManagerCompat.CryptoObject BuildCryptoObject()
    {
        Cipher cipher = CreateCipher();
        return new FingerprintManagerCompat.CryptoObject(cipher);
    }

    Cipher CreateCipher(bool retry = true)
    {
        IKey key = GetKey();
        Cipher cipher = Cipher.GetInstance(TRANSFORMATION);
        try
        {
            cipher.Init(CipherMode.EncryptMode, key);
        }
        catch (KeyPermanentlyInvalidatedException e)
        {
            _keystore.DeleteEntry(KEY_NAME);
            if (retry)
            {
                CreateCipher(false);
            }
            else
            {
                throw new Exception("Could not create the cipher for fingerprint authentication.", e);
            }
        }
        return cipher;
    }

    IKey GetKey()
    {
        if (!_keystore.IsKeyEntry(KEY_NAME))
        {
            CreateKey();
        }

        IKey secretKey = _keystore.GetKey(KEY_NAME, null);
        return secretKey;
    }

    void CreateKey()
    {

            KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME);
            KeyGenParameterSpec keyGenSpec =
                new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
                    .SetBlockModes(BLOCK_MODE)
                    .SetEncryptionPaddings(ENCRYPTION_PADDING)
                    .SetUserAuthenticationRequired(true)
                    .Build();
            keyGen.Init(keyGenSpec);
            keyGen.GenerateKey();


    }
Vitali
  • 341
  • 1
  • 5
  • 19

2 Answers2

2

Without seing more code it is hard to tell what is going on. It appears your code is executed on a background thread. You might try adding android.os.Looper.Prepare() as the first line inside CreateKey(). Hope it works.

  • Thanks for your response, I'll try it. The question is what different in Note 8 that gives this error. – Vitali Mar 07 '18 at 15:00
  • Could it be Android-version dependent? Which Android version does the Note 8 have, and which ones your other test devices? –  Mar 07 '18 at 15:31
  • I have tested Android 7 and Note has 7.1. Don't know if this can be a reason – Vitali Mar 07 '18 at 16:09
0

I have no idea what does it mean and how to fix it because it works well with other devices. It gives exception on row keyGen.Init(keyGenSpec)

It's a similar issue here. And as suggested, you can catch the exception and Initialize the key on the UI Thread according to failedOnNote8:

failedOnNote8=false;
try{
    keyGen.Init(keyGenSpec);
}catch (Exception e) {
    if(e.getMessage() != null && e.getMessage().equals("Can't create handler inside thread that has not called Looper.prepare()"))  {
        failedOnNote8 = true;
    }
}
if(failedOnNote8)
{
   //try to init the key on UI Thread.
}
Elvis Xia - MSFT
  • 10,801
  • 1
  • 13
  • 24