Created
October 3, 2019 17:05
-
-
Save jochasinga/d1a1d5a3dfd4ef9bf7eb3ed5c7e04dca to your computer and use it in GitHub Desktop.
Example of HeadSpin's HSFingerprintManager usage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*- | |
* #%L | |
* Demo Fingerprint Authentication Activity | |
* %% | |
* Copyright (C) 2019 Headspin Inc. | |
* %% | |
* #L% | |
*/ | |
package com.nextunicorn.app; | |
import android.annotation.TargetApi; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.os.CancellationSignal; | |
import android.content.Context; | |
import android.app.KeyguardManager; | |
import android.hardware.fingerprint.FingerprintManager; | |
import android.hardware.fingerprint.FingerprintManager.*; | |
import android.support.v4.app.ActivityCompat; | |
import android.widget.Toast; | |
import android.Manifest; | |
import android.content.Intent; | |
import android.content.pm.PackageManager; | |
import android.security.keystore.KeyProperties; | |
import java.security.KeyStore; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.NoSuchProviderException; | |
import javax.crypto.KeyGenerator; | |
import android.security.keystore.KeyGenParameterSpec; | |
import java.security.cert.CertificateException; | |
import java.security.InvalidAlgorithmParameterException; | |
import java.io.IOException; | |
import android.security.keystore.KeyPermanentlyInvalidatedException; | |
import android.support.annotation.RequiresApi; | |
import android.util.Log; | |
import java.security.InvalidKeyException; | |
import java.security.KeyStoreException; | |
import java.security.UnrecoverableKeyException; | |
import javax.crypto.NoSuchPaddingException; | |
import javax.crypto.SecretKey; | |
import javax.crypto.Cipher; | |
// Import from HeadSpin biometrics library | |
import io.headspin.instruments.fingerprint.HSFingerprintManager; | |
import io.headspin.instruments.fingerprint.HSFingerprintAuthCallback; | |
@TargetApi(28) | |
@RequiresApi(23) | |
class DemoFingerprintActivity extends AppCompatActivity { | |
private static String TAG = "DemoFingerprintActivity"; | |
private static String KEY_NAME = "hot_key"; | |
private HSFingerprintManager hsFingerprintManager; | |
private KeyguardManager keyguardManager; | |
private KeyStore keyStore; | |
private KeyGenerator keyGenerator; | |
private Cipher cipher; | |
private CryptoObject cryptoObject; | |
private CancellationSignal cancellationSignal; | |
/** | |
* Inherit [HSFingerprintAuthCallback] to get default toast messages or | |
* or [android.hardware.fingerprint.FingerprintManager.AuthenticationCallback] | |
* to implement your own callbacks. | |
*/ | |
private HSFingerprintCallback authCallback = new HSFingerprintAuthCallback() { | |
@Override | |
void onAuthenticationSucceeded(AuthenticationResult result) { | |
super.onAuthenticationSucceeded(result); | |
new Handler().postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
finish(); | |
} | |
}, 2000); | |
} | |
}; | |
@Override | |
void onCreate(Bundle savedInstanceState) { | |
Log.i(TAG, "creating DemoFingerprintActivity") | |
super.onCreate(savedInstanceState); | |
hsfingerprintManager = new HSFingerprintManager(this); | |
setContentView(R.layout.activity_fingerprint); | |
if (managersReady()) { | |
generateKey(); | |
if (initCipher()) { | |
cryptoObject = new CryptoObject(cipher); | |
cancellationSignal = new CancellationSignal(); | |
if (hsFingerprintManager.ready()) { | |
/* | |
* authenticate() sends authCallback to the underlying HSfingerprintService | |
* so it can be called by Headspin biometrics API. | |
*/ | |
hsFingerprintManager.authenticate(cryptoObject, cancellationSignal, | |
0, authCallback, null); | |
} | |
} | |
} | |
} | |
@Override | |
void onStop() { | |
super.onStop(); | |
// IMPORTANT: call close() to stop the HSFingerprintService. | |
hsFingerprintManager.close(); | |
} | |
/* | |
* This is a sample and thus using CBC Block mode should be good enough. | |
* However, please take care to implement a more secure key for your app. | |
*/ | |
private boolean initCipher() { | |
try { | |
cipher = Cipher.getInstance( | |
KeyProperties.KEY_ALGORITHM_AES + "/" | |
+ KeyProperties.BLOCK_MODE_CBC + "/" | |
+ KeyProperties.ENCRYPTION_PADDING_PKCS7); | |
} catch (NoSuchAlgorithmException e) { | |
throw RuntimeException("Failed to get Cipher", e); | |
} catch (NoSuchPaddingException e) { | |
throw RuntimeException("Failed to get Cipher", e); | |
} | |
try { | |
if (keyStore != null) { | |
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 e) { | |
throw RuntimeException("Failed to init Cipher", e); | |
} catch (CertificateException e) { | |
throw RuntimeException("Failed to init Cipher", e); | |
} catch (UnrecoverableKeyException e) { | |
throw RuntimeException("Failed to init Cipher", e); | |
} catch (IOException e) { | |
throw RuntimeException("Failed to init Cipher", e); | |
} catch (NoSuchAlgorithmException e) { | |
throw RuntimeException("Failed to init Cipher", e) | |
} catch (InvalidKeyException e) { | |
throw RuntimeException("Failed to init Cipher", e) | |
} | |
} | |
private void generateKey() { | |
try { | |
keyStore = KeyStore.getInstance("AndroidKeyStore"); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
try { | |
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, | |
"AndroidKeyStore"); | |
} catch (NoSuchAlgorithmException e) { | |
throw RuntimeException("Failed to get KeyGenerator instance", e); | |
} catch (NoSuchProviderException e) { | |
throw RuntimeException("Failed to get KeyGenerator instance", e); | |
} | |
try { | |
if (keyStore != null) { | |
keyStore.load(null); | |
keyGenerator.init(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 e ) { | |
throw RuntimeException(e); | |
} catch (InvalidAlgorithmParameterException e) { | |
throw RuntimeException(e); | |
} catch (CertificateException e) { | |
throw RuntimeException(e); | |
} catch (IOException e) { | |
throw RuntimeException(e); | |
} | |
} | |
private Boolean managersReady() { | |
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); | |
/* | |
* HSFingerprintManager fashions a ready() method that takes care of | |
* inquiring the wrapped FingerprintManager's readiness. | |
*/ | |
if ((keyguardManager == null) || (!hsfingerprintManager.ready())) { | |
return false; | |
} | |
if (keyguardManager.isKeyguardSecure == false) { | |
Toast.makeText(this, | |
"Lock screen security is not enabled in Settings", | |
Toast.LENGTH_LONG).show(); | |
return false; | |
} | |
if (ActivityCompat.checkSelfPermission(this, | |
Manifest.permission.USE_FINGERPRINT) != | |
PackageManager.PERMISSION_GRANTED) { | |
Toast.makeText(this, | |
"Fingerprint authentication permission not enabled", | |
Toast.LENGTH_LONG).show(); | |
return false; | |
} | |
if (hsfingerprintManager?.hasEnrolledFingerprints() == false) { | |
Toast.makeText(this, | |
"Register at least one fingerprint in Settings", | |
Toast.LENGTH_LONG).show(); | |
return false; | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment