The GeoGrabber app now supports fingerprint and face unlock for encrypted databases, providing a secure and convenient way to access your scan data.
✅ Android BiometricPrompt API - Supports fingerprint, face, and iris authentication
✅ Hardware-Backed Security - Passphrase encrypted with Android Keystore biometric keys
✅ Zero-Knowledge Design - Passphrase only decrypted after successful biometric authentication
✅ Fallback Support - Manual passphrase entry always available
✅ Auto-Invalidation - Keys invalidated when biometric enrollment changes
✅ Seamless Integration - Works alongside existing encryption system
BiometricAuthManager.java)
EncryptionManager.java)
DatabaseUnlockActivity.java)
App Launch
│
├─► Check if encryption enabled
│ └─► If NO → Open database directly
│ └─► If YES → Continue
│
├─► Check if passphrase cached
│ └─► If YES → Open database directly
│ └─► If NO → Show DatabaseUnlockActivity
│
├─► Check if biometric enabled
│ └─► If YES → Show biometric prompt
│ │ ├─► Success → Decrypt passphrase → Unlock database
│ │ └─► Fail → Show passphrase input
│ └─► If NO → Show passphrase input directly
│
└─► Passphrase Input
├─► Verify passphrase
├─► Cache in memory
└─► Open database
KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(
KEY_ALIAS_BIOMETRIC,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.setUserAuthenticationRequired(true) // ← Requires biometric auth
.setInvalidatedByBiometricEnrollment(true) // ← Auto-invalidates on changes
.build();
Key Properties:
When user enables biometric unlock:
EncryptionManager.unlockWithPassphrase()Storage:
SharedPreferences (biometric_prefs):
├─ encrypted_passphrase_biometric: [Base64 encrypted passphrase]
├─ biometric_iv: [Base64 initialization vector]
└─ biometric_enabled: true
When user launches app with biometric enabled:
DatabaseUnlockActivity shows biometric promptBiometricPrompt.CryptoObject provides authenticated cipherEncryptionManager.unlockWithPassphrase()MainActivityBiometricPrompt Configuration:
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("Unlock Database")
.setSubtitle("Use your fingerprint to unlock encrypted database")
.setNegativeButtonText("Use Passphrase") // Fallback option
.setConfirmationRequired(true) // Requires explicit confirmation
.build();
char[] not String (can be cleared)Arrays.fill(passphrase, '\0')BiometricAuthManager bioManager = new BiometricAuthManager(context, encryptionManager);
if (bioManager.isBiometricSupported()) {
// Device has biometric hardware and enrolled biometrics
String status = bioManager.getBiometricStatusMessage();
// "Biometric authentication available"
}
char[] passphrase = getUserPassphrase(); // Get from user input
if (bioManager.enableBiometricUnlock(passphrase)) {
// Successfully enabled
Log.i(TAG, "Biometric unlock enabled");
} else {
// Failed
Log.e(TAG, "Failed to enable biometric unlock");
}
// Always clear passphrase from memory
Arrays.fill(passphrase, '\0');
bioManager.authenticateWithBiometric(activity, new BiometricAuthManager.BiometricAuthCallback() {
@Override
public void onAuthenticationSucceeded(char[] passphrase) {
// Biometric auth successful, got decrypted passphrase
if (encryptionManager.unlockWithPassphrase(passphrase)) {
// Database unlocked
proceedToMainActivity();
}
Arrays.fill(passphrase, '\0'); // Clear from memory
}
@Override
public void onAuthenticationFailed() {
// User cancelled or chose "Use Passphrase"
showPassphraseInput();
}
@Override
public void onAuthenticationError(String errorMessage) {
// Error occurred (key invalidated, hardware unavailable, etc.)
Toast.makeText(context, errorMessage, Toast.LENGTH_LONG).show();
showPassphraseInput();
}
});
bioManager.disableBiometricUnlock();
// Biometric key deleted, encrypted passphrase removed
BiometricAuthManager(Context context, EncryptionManager encryptionManager)
| Method | Description | Returns |
|---|---|---|
isBiometricSupported() |
Check if device supports biometric auth | boolean |
isBiometricEnabled() |
Check if biometric unlock is enabled | boolean |
getBiometricStatusMessage() |
Get detailed biometric availability status | String |
enableBiometricUnlock(char[] passphrase) |
Enable biometric unlock with passphrase | boolean |
disableBiometricUnlock() |
Disable biometric unlock | void |
authenticateWithBiometric(activity, callback) |
Show biometric prompt and authenticate | void |
isBiometricKeyValid() |
Check if biometric key is still valid | boolean |
updateBiometricPassphrase(char[] newPassphrase) |
Update passphrase when changed | boolean |
public interface BiometricAuthCallback {
void onAuthenticationSucceeded(char[] passphrase);
void onAuthenticationFailed();
void onAuthenticationError(String errorMessage);
}
Cause: Device doesn’t have fingerprint sensor or face unlock
Solution: Use passphrase-only unlock
Cause: User hasn’t set up fingerprints/face in Android settings
Solution: Go to Settings → Security → Fingerprint/Face and enroll biometrics
Cause: User added or removed fingerprints after enabling biometric unlock
Solution: Disable and re-enable biometric unlock with passphrase
Cause: Device running Android < 6.0 or security update required
Solution: Update Android OS or use passphrase-only unlock
dependencies {
// Biometric authentication
implementation("androidx.biometric:biometric:1.1.0")
// Existing dependencies
implementation("net.zetetic:android-database-sqlcipher:4.5.4")
implementation("androidx.sqlite:sqlite:2.4.0")
}
<!-- Biometric authentication -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-feature android:name="android.hardware.fingerprint" android:required="false"/>
| Threat | Mitigation |
|---|---|
| Unauthorized access | Biometric auth required to decrypt passphrase |
| Passphrase extraction | Stored encrypted, only decrypted after biometric auth |
| Biometric spoofing | Android OS handles biometric security (secure element) |
| Key extraction | Android Keystore hardware-backed, keys cannot be extracted |
| Biometric changes | Keys auto-invalidated, user must re-enroll |
| Memory dumps | Passphrase cleared from memory after use |
| Failed attempts | Counter enforced, database wiped after 5 failures |
✅ Defense in Depth - Multiple layers (biometric + passphrase + keystore)
✅ Least Privilege - Biometric key only for passphrase decryption
✅ Fail Secure - Defaults to passphrase on any biometric error
✅ Audit Logging - All unlock attempts logged
✅ Secure Defaults - Biometric disabled by default, user must opt-in
Sicherheit beim Biometric Unlock:
Was ist sicherer?