Fingerprint Pro
A secure biometric authentication and keystore-based signature system for Flutter, providing both simple and advanced fingerprint/face unlock features with comprehensive security handling.
Features
🔐 Biometric Authentication
- Simple Mode: Easy biometric authentication using
local_authwrapper - Advanced Mode: Native keystore/keychain integration with biometric-protected cryptographic keys
- Support for fingerprint, face, and iris biometrics
- Platform-specific optimizations (AndroidX BiometricPrompt, iOS LocalAuthentication)
🔑 Cryptographic Key Management
- ECDSA Key Generation: Secure Elliptic Curve Digital Signature Algorithm key pairs
- Biometric-Protected Keys: Keys require biometric authentication for use
- Hardware Security: Utilizes secure hardware (StrongBox, Secure Enclave) when available
- Key Lifecycle Management: Generate, use, and remove keys securely
🛡️ Security Features
- No Biometric Data Storage: Never stores fingerprint or face data
- OS-Provided Authentication: Uses only system-provided biometric APIs
- Secure Key Storage: Keys stored in platform keystores (Android KeyStore, iOS Keychain)
- Signature Verification: Server-side signature verification support
Installation
Add this to your package's pubspec.yaml file:
dependencies:
fingerprint_pro: ^1.0.0
Platform Setup
Android Setup
- Permissions: Add biometric permission to
android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<application>
<!-- Your application configuration -->
</application>
</manifest>
- API Level: Ensure
minSdkVersionis 23 or higher inandroid/app/build.gradle:
android {
defaultConfig {
minSdkVersion 23
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
}
- ProGuard Rules: If using ProGuard, add these rules to
proguard-rules.pro:
-keep class androidx.biometric.** { *; }
-keep class android.security.keystore.** { *; }
iOS Setup
- Info.plist: Add biometric usage descriptions to
ios/Runner/Info.plist:
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to authenticate you securely.</string>
<key>NSBiometricUsageDescription</key>
<string>We use Touch ID/Face ID to authenticate you securely.</string>
- Minimum iOS Version: Set minimum deployment target to iOS 11.0 or higher.
Usage
Simple Biometric Authentication
import 'package:fingerprint_pro/fingerprint_pro.dart';
final fingerprintPro = FingerprintPro();
// Check if biometric authentication is available
bool canAuthenticate = await fingerprintPro.canAuthenticate();
// Get available biometric types
List<BiometricType> biometrics = await fingerprintPro.getAvailableBiometrics();
// Authenticate user
BiometricResult result = await fingerprintPro.authenticate(
reason: 'Please authenticate to access your account',
options: BiometricOptions(
stickyAuth: false,
useErrorDialogs: true,
),
);
if (result.success) {
print('Authentication successful!');
} else {
print('Authentication failed: ${result.error?.description}');
}
Advanced Key Management
import 'package:fingerprint_pro/fingerprint_pro.dart';
import 'dart:convert';
final fingerprintPro = FingerprintPro();
// Generate a biometric-protected key pair
KeyGenerationResult keyResult = await fingerprintPro.generateKeyPair(
keyAlias: 'user_auth_key',
options: KeyGenerationOptions(
userAuthenticationRequired: true,
useEcdsa: true,
useSecureHardware: true,
),
);
if (keyResult.success) {
// Share the public key with your server for signature verification
String publicKeyPem = keyResult.publicKeyPem!;
// Send publicKeyPem to your server
}
// Sign data with biometric authentication
String data = 'Important data to sign';
Uint8List dataBytes = utf8.encode(data);
SignatureResult signResult = await fingerprintPro.signWithKey(
keyAlias: 'user_auth_key',
data: dataBytes,
);
if (signResult.success) {
// Send signature and original data to server for verification
Uint8List signature = signResult.signature!;
// Server can verify using the public key
}
// Remove key when no longer needed
await fingerprintPro.removeKey('user_auth_key');
Error Handling
The package provides comprehensive error handling:
try {
BiometricResult result = await fingerprintPro.authenticate(reason: 'Login');
if (result.success) {
// Success
} else {
// Handle specific errors
switch (result.error) {
case BiometricError.notAvailable:
// Biometric authentication not available
break;
case BiometricError.notEnrolled:
// No biometric credentials enrolled
break;
case BiometricError.cancelled:
// User cancelled authentication
break;
default:
// Other errors
break;
}
}
} on FingerprintProException catch (e) {
// Handle platform-specific errors
print('Error: ${e.message}');
}
Server-Side Signature Verification
For the advanced key management mode, you can verify signatures on your server:
Node.js Example
const crypto = require('crypto');
// Public key from the mobile app (PEM format)
const publicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----`;
const publicKey = crypto.createPublicKey({
key: publicKeyPem,
format: 'pem',
type: 'spki'
});
// Data that was signed
const data = 'Important data to sign';
// Signature from the mobile app (base64 encoded)
const signature = 'base64-encoded-signature';
// Verify signature
const isValid = crypto.verify(
'sha256',
Buffer.from(data),
{
key: publicKey,
dsaEncoding: 'ieee-p1363'
},
Buffer.from(signature, 'base64')
);
console.log('Signature valid:', isValid);
Python Example
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.exceptions import InvalidSignature
# Public key from the mobile app (PEM format)
public_key_pem = b"""-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""
public_key = serialization.load_pem_public_key(public_key_pem)
# Data that was signed
data = b"Important data to sign"
# Signature from the mobile app (base64 decoded)
signature = base64.b64decode("base64-encoded-signature")
try:
public_key.verify(signature, data, ec.ECDSA(hashes.SHA256()))
print("Signature is valid")
except InvalidSignature:
print("Signature is invalid")
Privacy Notice
fingerprint_pro does not store any biometric data. All biometric authentication is handled by the operating system's secure biometric APIs:
- Android: Uses AndroidX BiometricPrompt with Android KeyStore
- iOS: Uses LocalAuthentication framework with Keychain
Biometric data never leaves the device and is not accessible to the app or stored in any form.
API Reference
Classes
FingerprintPro
Main class for biometric authentication and key management.
Methods:
Future<bool> canAuthenticate()- Check if biometric authentication is availableFuture<List<BiometricType>> getAvailableBiometrics()- Get available biometric typesFuture<BiometricResult> authenticate({required String reason, BiometricOptions options})- Authenticate userFuture<KeyGenerationResult> generateKeyPair({required String keyAlias, KeyGenerationOptions options})- Generate key pairFuture<SignatureResult> signWithKey({required String keyAlias, required Uint8List data})- Sign dataFuture<bool> removeKey(String keyAlias)- Remove keyFuture<bool> keyExists(String keyAlias)- Check if key existsFuture<List<String>> listKeys()- List all keys
BiometricOptions
Configuration options for biometric authentication.
Properties:
bool stickyAuth- Whether authentication dialog stays open until success/failurebool sensitiveTransaction- Whether this is a sensitive transaction (Android)String? reason- Custom reason for authentication promptbool useErrorDialogs- Whether to show error dialogs on failure
KeyGenerationOptions
Configuration options for key generation.
Properties:
bool userAuthenticationRequired- Whether biometric authentication is required for key usageint userAuthenticationValiditySeconds- How long authentication remains valid (Android)bool useEcdsa- Whether to use ECDSA (recommended) or RSAint keySize- Key size in bits (ignored for ECDSA)bool useSecureHardware- Whether to use secure hardware when available
Enums
BiometricType
Available biometric authentication types:
fingerprint- Fingerprint authenticationface- Face authentication (Face ID)iris- Iris authenticationstrong- Strong biometric (hardware-backed)weak- Weak biometric (software-based)
BiometricError
Possible error conditions:
notAvailable- Biometric authentication not availablenotEnrolled- No biometric credentials enrolledcancelled- User cancelled authenticationauthenticationFailed- Authentication failedunsupported- Biometric authentication not supportedpermissionDenied- Permission deniedtemporarilyUnavailable- Temporarily unavailablepermanentlyUnavailable- Permanently unavailabletimeout- Authentication timed outplatformError- Platform-specific errorkeyGenerationFailed- Key generation failedkeyNotFound- Key not foundsignatureFailed- Signature operation failedinvalidKeySpec- Invalid key specification
Testing
Run the tests:
flutter test
Run the example app:
cd example
flutter run
Publishing
To publish to pub.flutter-io.cn:
- Ensure all tests pass
- Update version in
pubspec.yaml - Run
flutter pub publish --dry-runto verify - Run
flutter pub publishto publish
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
Development Setup
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For support and questions:
Changelog
See CHANGELOG.md for version history and changes.