Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Fingerprint API and Private/Public keys

Tags:

When I enrol first and only fingerprint and generate KeyPair the PrivateKey gets invalidated when I use it for the second time. This happens only once. Am I the only one having this issue? Is there something wrong with my code?

I cannot use any other key as I'm using PrivateKey to sign data.

Steps:

  1. Wipe all fingerprints
  2. Enrol one fingerprint
  3. Generate KeyPair and use FingerprintManager :: authenticate
  4. During next use of FingerprintManager :: authenticate PrivateKey gets permanently invalidated. This happens only for the first time

Below the code where I generate the KeyPair

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(null);
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
generator.initialize(new KeyGenParameterSpec.Builder("key_name", KeyProperties.PURPOSE_SIGN)
    .setDigests(digest) // I have defined digest before
    .setSignaturePaddings(paddings) // I have defined paddings before
    .setUserAuthenticationRequired(true)
    .build());
generator.generateKeyPair();

And here is the code where I invoke fingerprint authentication for data signing:

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
Signature signature = Signature.getInstance("signing_algorithm");
PrivateKey privateKey = (PrivateKey) keyStore.getKey("key_name", null);
signature.initSign(privateKey); // Here I get KeyPermanentlyInvalidatedException
CryptoObject crypto = new CryptoObject(signature);
FingerprintManager fingerprintManager = context.getSystemService(FingerprintManager.class);
CancellationSignal cancellationSignal = new CancellationSignal();
AuthenticationCallback authenticationCallback = new AuthenticationCallback() {
    ...
};
fingerprintManager.authenticate(crypto, cancelationSignal, 0, authenticationCallback, null);
like image 566
Toochka Avatar asked Oct 25 '16 14:10

Toochka


People also ask

Is Android biometric authentication secure?

Research conducted by F-Secure Labs revealed that 70% of the sampled mobile applications on Google Play store that have implemented biometric authentication can be easily bypassed. Additionally, 50% of these applications store sensitive data, which can be retrieved by attackers without valid biometric credentials.

Is Android keystore secure?

The Android Keystore provides APIs to perform cryptographic operations within this trusted environment and receive the result. It was introduced in API 18 (Android 4.3). A strongbox backed Android Keystore is currently the most secure and recommended type of keystore.

How do I enable fingerprint on Android emulator?

Run your Android emulator and go to Settings->Security & location->Fingerprint. If you have set up your PIN, enter it on your emulator. If you haven't set up your PIN, Android emulator will prompt you to add it at this point. Click Add fingerprint.


1 Answers

i try this link and work perfectly .

First you need to set Minimum sdk look like the Picture

Image

Second set Permission in Mainfest

   <uses-permission android:name="android.permission.USE_FINGERPRINT" />

Third

generateKey() function which generates an encryption key which is then stored securely on the device.

cipherInit() function that initializes the cipher that will be used to create the encrypted FingerprintManager.

CryptoObject instance and various other checks before initiating the authentication process which is implemented inside onCreate() method.

FingerPrintActivty.java

import android.Manifest;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
 
 
public class FingerprintActivity extends AppCompatActivity {
 
 
   private KeyStore keyStore;
   // Variable used for storing the key in the Android Keystore container
   private static final String KEY_NAME = "androidHive";
   private Cipher cipher;
   private TextView textView;
 
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_fingerprint);
 
 
       // Initializing both Android Keyguard Manager and Fingerprint Manager
       KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
       FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
 
 
       textView = (TextView) findViewById(R.id.errorText);
 
 
       // Check whether the device has a Fingerprint sensor.
       if(!fingerprintManager.isHardwareDetected()){
           /**
            * An error message will be displayed if the device does not contain the fingerprint hardware.
            * However if you plan to implement a default authentication method,
            * you can redirect the user to a default authentication activity from here.
            * Example:
            * Intent intent = new Intent(this, DefaultAuthenticationActivity.class);
            * startActivity(intent);
            */
           textView.setText("Your Device does not have a Fingerprint Sensor");
       }else {
           // Checks whether fingerprint permission is set on manifest
           if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
               textView.setText("Fingerprint authentication permission not enabled");
           }else{
               // Check whether at least one fingerprint is registered
               if (!fingerprintManager.hasEnrolledFingerprints()) {
                   textView.setText("Register at least one fingerprint in Settings");
               }else{
                   // Checks whether lock screen security is enabled or not
                   if (!keyguardManager.isKeyguardSecure()) {
                       textView.setText("Lock screen security not enabled in Settings");
                   }else{
                       generateKey();
 
 
                       if (cipherInit()) {
                           FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
                           FingerprintHandler helper = new FingerprintHandler(this);
                           helper.startAuth(fingerprintManager, cryptoObject);
                       }
                   }
               }
           }
       }
   }
 
 
   @TargetApi(Build.VERSION_CODES.M)
   protected void generateKey() {
       try {
           keyStore = KeyStore.getInstance("AndroidKeyStore");
       } catch (Exception e) {
           e.printStackTrace();
       }
 
 
       KeyGenerator keyGenerator;
       try {
           keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
       } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
           throw new RuntimeException("Failed to get KeyGenerator instance", e);
       }
 
 
       try {
           keyStore.load(null);
           keyGenerator.init(new
                   KeyGenParameterSpec.Builder(KEY_NAME,
                   KeyProperties.PURPOSE_ENCRYPT |
                           KeyProperties.PURPOSE_DECRYPT)
                   .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                   .setUserAuthenticationRequired(true)
                   .setEncryptionPaddings(
                           KeyProperties.ENCRYPTION_PADDING_PKCS7)
                   .build());
           keyGenerator.generateKey();
       } catch (NoSuchAlgorithmException |
               InvalidAlgorithmParameterException
               | CertificateException | IOException e) {
           throw new RuntimeException(e);
       }
   }
 
 
   @TargetApi(Build.VERSION_CODES.M)
   public boolean cipherInit() {
       try {
           cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
       } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
           throw new RuntimeException("Failed to get Cipher", e);
       }
 
 
       try {
           keyStore.load(null);
           SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
                   null);
           cipher.init(Cipher.ENCRYPT_MODE, key);
           return true;
       } catch (KeyPermanentlyInvalidatedException e) {
           return false;
       } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
           throw new RuntimeException("Failed to init Cipher", e);
       }
   }
}

FingerprintAuthenticationHandler.Class

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.CancellationSignal;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.TextView;
 
 
/**
* Created by whit3hawks on 11/16/16.
*/
public class FingerprintHandler extends FingerprintManager.AuthenticationCallback {
 
 
   private Context context;
 
 
   // Constructor
   public FingerprintHandler(Context mContext) {
       context = mContext;
   }
 
 
   public void startAuth(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) {
       CancellationSignal cancellationSignal = new CancellationSignal();
       if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
           return;
       }
       manager.authenticate(cryptoObject, cancellationSignal, 0, this, null);
   }
 
 
   @Override
   public void onAuthenticationError(int errMsgId, CharSequence errString) {
       this.update("Fingerprint Authentication error\n" + errString, false);
   }
 
 
   @Override
   public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
       this.update("Fingerprint Authentication help\n" + helpString, false);
   }
 
 
   @Override
   public void onAuthenticationFailed() {
       this.update("Fingerprint Authentication failed.", false);
   }
 
 
   @Override
   public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
       this.update("Fingerprint Authentication succeeded.", true);
   }
 
 
   public void update(String e, Boolean success){
       TextView textView = (TextView) ((Activity)context).findViewById(R.id.errorText);
       textView.setText(e);
       if(success){
           textView.setTextColor(ContextCompat.getColor(context,R.color.colorPrimaryDark));
       }
   }
}

Hope it help.

like image 195
Mohammad Hossein jfp Avatar answered Nov 09 '22 05:11

Mohammad Hossein jfp