Fingerprint Pro

pub package License: MIT

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_auth wrapper
  • 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

  1. 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>
  1. API Level: Ensure minSdkVersion is 23 or higher in android/app/build.gradle:
android {
    defaultConfig {
        minSdkVersion 23
        targetSdkVersion 33
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
}
  1. ProGuard Rules: If using ProGuard, add these rules to proguard-rules.pro:
-keep class androidx.biometric.** { *; }
-keep class android.security.keystore.** { *; }

iOS Setup

  1. 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>
  1. 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 available
  • Future<List<BiometricType>> getAvailableBiometrics() - Get available biometric types
  • Future<BiometricResult> authenticate({required String reason, BiometricOptions options}) - Authenticate user
  • Future<KeyGenerationResult> generateKeyPair({required String keyAlias, KeyGenerationOptions options}) - Generate key pair
  • Future<SignatureResult> signWithKey({required String keyAlias, required Uint8List data}) - Sign data
  • Future<bool> removeKey(String keyAlias) - Remove key
  • Future<bool> keyExists(String keyAlias) - Check if key exists
  • Future<List<String>> listKeys() - List all keys

BiometricOptions

Configuration options for biometric authentication.

Properties:

  • bool stickyAuth - Whether authentication dialog stays open until success/failure
  • bool sensitiveTransaction - Whether this is a sensitive transaction (Android)
  • String? reason - Custom reason for authentication prompt
  • bool useErrorDialogs - Whether to show error dialogs on failure

KeyGenerationOptions

Configuration options for key generation.

Properties:

  • bool userAuthenticationRequired - Whether biometric authentication is required for key usage
  • int userAuthenticationValiditySeconds - How long authentication remains valid (Android)
  • bool useEcdsa - Whether to use ECDSA (recommended) or RSA
  • int 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 authentication
  • face - Face authentication (Face ID)
  • iris - Iris authentication
  • strong - Strong biometric (hardware-backed)
  • weak - Weak biometric (software-based)

BiometricError

Possible error conditions:

  • notAvailable - Biometric authentication not available
  • notEnrolled - No biometric credentials enrolled
  • cancelled - User cancelled authentication
  • authenticationFailed - Authentication failed
  • unsupported - Biometric authentication not supported
  • permissionDenied - Permission denied
  • temporarilyUnavailable - Temporarily unavailable
  • permanentlyUnavailable - Permanently unavailable
  • timeout - Authentication timed out
  • platformError - Platform-specific error
  • keyGenerationFailed - Key generation failed
  • keyNotFound - Key not found
  • signatureFailed - Signature operation failed
  • invalidKeySpec - 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:

  1. Ensure all tests pass
  2. Update version in pubspec.yaml
  3. Run flutter pub publish --dry-run to verify
  4. Run flutter pub publish to publish

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Development Setup

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. 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.

Libraries

fingerprint_pro