{"id":32272932,"url":"https://github.com/chamodanethra/biometric_signature","last_synced_at":"2026-04-01T19:42:08.096Z","repository":{"id":65564354,"uuid":"593367405","full_name":"chamodanethra/biometric_signature","owner":"chamodanethra","description":"Hardware-backed biometric authentication for Flutter. Create cryptographic signatures using device biometrics with keys stored in Secure Enclave/StrongBox/Windows Hello.","archived":false,"fork":false,"pushed_at":"2026-03-04T06:30:40.000Z","size":2215,"stargazers_count":15,"open_issues_count":3,"forks_count":19,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-03-21T03:02:36.286Z","etag":null,"topics":["android","biometric-authentication","cryptography","flutter","ios","macos","secure-enclave","security","strongbox","windows","windows-hello"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/biometric_signature","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chamodanethra.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-25T20:48:51.000Z","updated_at":"2026-03-03T07:55:22.000Z","dependencies_parsed_at":"2024-06-03T00:55:27.129Z","dependency_job_id":"1feb55c4-d3b7-443a-81d9-1eac82e3b1cd","html_url":"https://github.com/chamodanethra/biometric_signature","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/chamodanethra/biometric_signature","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chamodanethra%2Fbiometric_signature","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chamodanethra%2Fbiometric_signature/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chamodanethra%2Fbiometric_signature/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chamodanethra%2Fbiometric_signature/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chamodanethra","download_url":"https://codeload.github.com/chamodanethra/biometric_signature/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chamodanethra%2Fbiometric_signature/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31085299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-28T02:23:35.801Z","status":"ssl_error","status_checked_at":"2026-03-28T02:23:32.528Z","response_time":79,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","biometric-authentication","cryptography","flutter","ios","macos","secure-enclave","security","strongbox","windows","windows-hello"],"created_at":"2025-10-22T23:10:31.518Z","updated_at":"2026-04-01T19:42:08.081Z","avatar_url":"https://github.com/chamodanethra.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# biometric_signature\n\n**Stop just unlocking the UI. Start proving the identity.**\n\nStandard biometric integrations typically return only a boolean indicating whether authentication succeeded.\n`biometric_signature` provides a complete biometric solution:\n\n1.  **Cryptographic Proof (Core Feature):** Generates a **verifiable cryptographic signature** using a private key stored in hardware (Secure Enclave / StrongBox). This allows your backend to mathematically verify the user's identity, preventing replay attacks and API hooks.\n2.  **Simple Authentication:** Supports standard biometric prompts (returning success/failure) for local UI gating or quick re-authentication, with full support for Android biometric strength levels and device credentials.\n\nEven if an attacker bypasses or hooks biometric APIs, your backend will still reject the request because **the attacker cannot forge a hardware-backed signature without the private key**.\n\n## Features\n\n- **Cryptographic Proof Of Identity:** Hardware-backed RSA (Android) or ECDSA (all platforms) signatures that your backend can independently verify.\n- **Decryption Support:** \n  - **RSA**: RSA/ECB/PKCS1Padding (Android native, iOS/macOS via wrapped software key)\n  - **EC**: ECIES (`eciesEncryptionStandardX963SHA256AESGCM`)\n- **Hardware Security:** Uses Secure Enclave (iOS/macOS) and Keystore/StrongBox (Android).\n- **Hybrid Architectures:**\n  - **Android Hybrid EC:** Hardware EC signing + software ECIES decryption. Software EC private key is AES-wrapped using a Keystore/StrongBox AES-256 master key that requires biometric authentication for every unwrap.\n  - **iOS/macOS Hybrid RSA:** Software RSA key for **both signing and decryption**, wrapped using ECIES with Secure Enclave EC public key. Hardware EC is only used for wrapping/unwrapping.\n- **Key Invalidation:** Keys can be bound to biometric enrollment state (fingerprint/Face ID changes).\n- **Device Credentials:** Optional PIN/Pattern/Password fallback on Android.\n- **Simple Prompt (No Crypto):** Verify user presence without key operations. Supports device-credential fallback and Android biometric strength selection.\n\n\n## Security Architecture\n\n### Key Modes\n\nThe plugin supports different operational modes depending on the platform:\n\n#### Android\n\nAndroid supports three key modes:\n\n1. **RSA Mode** (`SignatureType.rsa`):\n   - Hardware-backed RSA-2048 signing (Keystore/StrongBox)\n   - Optional RSA decryption (PKCS#1 padding)\n   - Private key never leaves secure hardware\n\n2. **EC Signing-Only** (`SignatureType.ecdsa`, `enableDecryption: false`):\n   - Hardware-backed P-256 key in Keystore/StrongBox\n   - ECDSA signing only\n   - No decryption support\n\n3. **Hybrid EC Mode** (`SignatureType.ecdsa`, `enableDecryption: true`):\n   - Hardware EC key for signing\n   - Software EC key for ECIES decryption\n   - Software EC private key encrypted using AES-256 GCM master key (Keystore/StrongBox)\n   - Per-operation biometric authentication required for decryption\n\n#### iOS / macOS\n\nApple platforms support two key modes (Secure Enclave only supports EC keys natively):\n\n1. **EC Mode** (`SignatureType.ecdsa`):\n   - Hardware-backed P-256 key in Secure Enclave\n   - ECDSA signing\n   - Native ECIES decryption (`eciesEncryptionStandardX963SHA256AESGCM`)\n   - Single key for both operations\n\n2. **RSA Mode** (`SignatureType.rsa`) - Hybrid Architecture:\n   - Software RSA-2048 key for **both signing and decryption**\n   - RSA private key wrapped using ECIES with Secure Enclave EC public key\n   - Hardware EC key is **only** used for wrapping/unwrapping the RSA key\n   - Wrapped RSA key stored in Keychain as `kSecClassGenericPassword`\n   - Per-operation biometric authentication required to unwrap RSA key\n\n\n\n### Workflow Overview\n\n1.  **Enrollment**\n\n    User authenticates → hardware generates a signing key.\n\n    Hybrid modes additionally generate a software decryption key, which is then encrypted using secure hardware.\n2.  **Signing** \n\n    Biometric prompt is shown\n\n    Hardware unlocks the signing key, and a verifiable signature is produced.\n3.  **Decryption**\n\n    A biometric prompt is shown again.\n\n    Hybrid modes unwrap the software private key using hardware-protected AES-GCM, then decrypt the payload.\n4.  **Backend Verification** \n\n    The backend verifies signatures using the registered public key.\n\n    Verification **must not** be performed on the client.\n\n\n\n## Backend Verification\n\nPerform verification on the server. Below are reference implementations.\n\n### Node.js\n```javascript\nconst crypto = require('crypto');\n\nfunction verifySignature(publicKeyPem, payload, signatureBase64) {\n    const verify = crypto.createVerify('SHA256');\n    verify.update(payload); // The original string you sent to the plugin\n    verify.end();\n\n    // Returns true if valid\n    return verify.verify(publicKeyPem, Buffer.from(signatureBase64, 'base64'));\n}\n```\n### Python\n```python\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import padding\nfrom cryptography.hazmat.primitives import serialization\nimport base64\n\ndef verify_signature(public_key_pem_str, payload_str, signature_base64_str):\n    public_key = serialization.load_pem_public_key(public_key_pem_str.encode())\n    signature = base64.b64decode(signature_base64_str)\n    \n    try:\n        # Assuming RSA (For EC, use ec.ECDSA(hashes.SHA256()))\n        public_key.verify(\n            signature,\n            payload_str.encode(),\n            padding.PKCS1v15(),\n            hashes.SHA256()\n        )\n        return True\n    except Exception:\n        return False\n```\n\n### Go\n```go\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/pem\"\n\t\"fmt\"\n)\n\nfunc verify(pubPemStr, payload, sigBase64 string) error {\n\tblock, _ := pem.Decode([]byte(pubPemStr))\n\tpub, _ := x509.ParsePKIXPublicKey(block.Bytes)\n\trsaPub := pub.(*rsa.PublicKey)\n\n\thashed := sha256.Sum256([]byte(payload))\n\tsig, _ := base64.StdEncoding.DecodeString(sigBase64)\n\n\treturn rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, hashed[:], sig)\n}\n```\n\n## Getting Started\n\nTo get started with Biometric Signature, follow these steps:\n\n1. Add the package to your project by including it in your `pubspec.yaml` file:\n\n```yaml\ndependencies:\n  biometric_signature: ^10.2.0\n```\n\n|             | Android | iOS   | macOS  | Windows |\n|-------------|---------|-------|--------|--------|\n| **Support** | SDK 24+ | 13.0+ | 10.15+ | 10+    |\n\n### iOS Integration\n\nThis plugin works with Touch ID **or** Face ID. To use Face ID in available devices,\nyou need to add:\n\n```xml\n\n\u003cdict\u003e\n    \u003ckey\u003eNSFaceIDUsageDescription\u003c/key\u003e\n    \u003cstring\u003eThis app is using FaceID for authentication\u003c/string\u003e\n\u003c/dict\u003e\n```\n\nto your Info.plist file.\n\n### Android Integration\n\n#### Activity Changes\n\nThis plugin requires the use of a `FragmentActivity` instead of `Activity`. Update your `MainActivity.kt` to extend `FlutterFragmentActivity`:\n\n```kotlin\nimport io.flutter.embedding.android.FlutterFragmentActivity\n\nclass MainActivity : FlutterFragmentActivity() {\n}\n```\n\n#### Permissions\n\nUpdate your project's `AndroidManifest.xml` file to include the\n`USE_BIOMETRIC` permission.\n\n```xml\n\n\u003cmanifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com.example.app\"\u003e\n    \u003cuses-permission android:name=\"android.permission.USE_BIOMETRIC\" /\u003e\n\u003c/manifest\u003e\n```\n\n### macOS Integration\n\nThis plugin works with Touch ID on supported Macs. To use Touch ID, you need to:\n\n1. Add the required entitlements to your macOS app.\n\nOpen your macOS project's entitlements file (typically located at `macos/Runner/DebugProfile.entitlements` and `macos/Runner/Release.entitlements`) and ensure it includes:\n\n```xml\n\u003ckey\u003ecom.apple.security.device.usb\u003c/key\u003e\n\u003cfalse/\u003e\n\u003ckey\u003ecom.apple.security.device.bluetooth\u003c/key\u003e\n\u003cfalse/\u003e\n\u003ckey\u003ekeychain-access-groups\u003c/key\u003e\n\u003carray\u003e\n    \u003cstring\u003e$(AppIdentifierPrefix)com.yourdomain.yourapp\u003c/string\u003e\n\u003c/array\u003e\n```\n\nReplace `com.yourdomain.yourapp` with your actual bundle identifier.\n\n2. Ensure CocoaPods is properly configured in your `macos/Podfile`. The plugin requires macOS 10.15 or later:\n\n```ruby\nplatform :osx, '10.15'\n```\n\n### Windows Integration\n\n### Windows Integration\n\nThis plugin uses **Windows Hello** (`Windows.Security.Credentials.KeyCredentialManager`) for biometric authentication on Windows 10 and later. Keys are typically backed by the device's **TPM (Trusted Platform Module)** for hardware-grade security.\n\n**Platform Limitations:**\n- **Key Type**: Windows Hello only supports **RSA-2048** keys (ECDSA requests are automatically promoted to RSA).\n- **Authentication**: Windows Hello **always authenticates** during key creation (`enforceBiometric` is effectively always `true`).\n- **Configuration**: `setInvalidatedByBiometricEnrollment` and `useDeviceCredentials` arguments are ignored on this platform.\n- **Decryption**: **Not supported**. The Windows Hello API is designed primarily for authentication (signing) and does not expose general decryption capabilities for these keys.\n\nNo additional configuration is required. The plugin will automatically use Windows Hello when available.\n\n### Common Setup\n\n1. Import the package in your Dart code:\n\n```dart\nimport 'package:biometric_signature/biometric_signature.dart';\n```\n\n2. Initialize the Biometric Signature instance:\n\n```dart\n\nfinal biometricSignature = BiometricSignature();\n```\n\n## Usage\n\nThis package simplifies server authentication using biometrics. The following image from Android Developers Blog illustrates the basic use case:\n\n![biometric_signature](https://raw.githubusercontent.com/chamodanethra/biometric_signature/main/assets/usecase.png)\n\nWhen a user enrolls in biometrics, a key pair is generated. The private key is securely stored on the device, while the public key is sent to a server for registration. To authenticate, the user is prompted to use their biometrics, unlocking the private key. A cryptographic signature is then generated and sent to the server for verification. If the server successfully verifies the signature, it returns an appropriate response, authorizing the user.\n\n### Biometric Decryption\n\nThe plugin also supports secure decryption, ensuring that sensitive data transmitted from the server can only be accessed by the authenticated user on their specific device.\n\n![Biometric Decryption Lifecycle](https://raw.githubusercontent.com/chamodanethra/biometric_signature/main/assets/usecase-2.jpeg)\n\n1.  **Key Creation**: The device generates a key pair (EC or RSA) in secure hardware.\n2.  **Registration**: The public key is sent to the backend server.\n3.  **Encryption**: The server encrypts the sensitive payload using the public key.\n4.  **Authentication**: The encrypted payload is sent to the device. The user must authenticate biometrically to proceed.\n5.  **Decryption**: Once authenticated, the secure hardware uses the private key to decrypt the payload, revealing the plaintext data to the app.\n\n## Class: BiometricSignaturePlugin\n\nThis class provides methods to manage and utilize biometric authentication for secure server interactions. It supports both Android and iOS platforms.\n\n### `createKeys({ config, keyFormat, promptMessage })`\n\nGenerates a new key pair (RSA 2048 or EC) for biometric authentication. The private key is securely stored on the device.\n\n- **Parameters**:\n  - `config`: `CreateKeysConfig` with platform options (see below)\n  - `keyFormat`: Output format (`KeyFormat.base64`, `pem`, `hex`)\n  - `promptMessage`: Custom authentication prompt message\n\n- **Returns**: `Future\u003cKeyCreationResult\u003e`.\n  - `publicKey`: The formatted public key string (Base64 or PEM).\n  - `code`: `BiometricError` code (e.g., `success`, `userCanceled`).\n  - `error`: Descriptive error message.\n\n#### CreateKeysConfig Options\n\n| Option | Platforms | Description |\n|--------|-----------|-------------|\n| `signatureType` | Android/iOS/macOS | `SignatureType.rsa` or `SignatureType.ecdsa` |\n| `enforceBiometric` | Android/iOS/macOS | Require biometric during key creation |\n| `setInvalidatedByBiometricEnrollment` | Android/iOS/macOS | Invalidate key on biometric changes |\n| `useDeviceCredentials` | Android/iOS/macOS | Allow PIN/passcode fallback |\n| `enableDecryption` | Android | Enable decryption capability |\n| `promptSubtitle` | Android | Subtitle for biometric prompt |\n| `promptDescription` | Android | Description for biometric prompt |\n| `cancelButtonText` | Android | Cancel button text |\n\n```dart\nfinal result = await biometricSignature.createKeys(\n  keyFormat: KeyFormat.pem,\n  promptMessage: 'Authenticate to create keys',\n  config: CreateKeysConfig(\n    signatureType: SignatureType.rsa,\n    enforceBiometric: true,\n    setInvalidatedByBiometricEnrollment: true,\n    useDeviceCredentials: false,\n    enableDecryption: true, // Android only\n  ),\n);\n\nif (result.code == BiometricError.success) {\n   print('Public Key: ${result.publicKey}');\n}\n```\n\n### `createSignature({ payload, config, signatureFormat, keyFormat, promptMessage })`\n\nPrompts the user for biometric authentication and generates a cryptographic signature.\n\n- **Parameters**:\n  - `payload`: The data to sign\n  - `config`: `CreateSignatureConfig` with platform options\n  - `signatureFormat`: Output format for signature\n  - `keyFormat`: Output format for public key\n  - `promptMessage`: Custom authentication prompt\n\n#### CreateSignatureConfig Options\n\n| Option | Platforms | Description |\n|--------|-----------|-------------|\n| `allowDeviceCredentials` | Android | Allow PIN/pattern fallback |\n| `promptSubtitle` | Android | Subtitle for biometric prompt |\n| `promptDescription` | Android | Description for biometric prompt |\n| `cancelButtonText` | Android | Cancel button text |\n| `shouldMigrate` | iOS | Migrate from legacy keychain storage |\n\n- **Returns**: `Future\u003cSignatureResult\u003e`.\n  - `signature`: The signed payload.\n  - `publicKey`: The public key.\n  - `code`: `BiometricError` code.\n\n```dart\nfinal result = await biometricSignature.createSignature(\n  payload: 'Data to sign',\n  promptMessage: 'Please authenticate',\n  signatureFormat: SignatureFormat.base64,\n  keyFormat: KeyFormat.base64,\n  config: CreateSignatureConfig(\n    allowDeviceCredentials: false,\n  ),\n);\n```\n\n### `decrypt({ payload, payloadFormat, config, promptMessage })`\n\nDecrypts the given payload using the private key and biometrics.\n\n- **Parameters**:\n  - `payload`: The encrypted data\n  - `payloadFormat`: Format of encrypted data (`PayloadFormat.base64`, `hex`)\n  - `config`: `DecryptConfig` with platform options\n  - `promptMessage`: Custom authentication prompt\n\n#### DecryptConfig Options\n\n| Option | Platforms | Description |\n|--------|-----------|-------------|\n| `allowDeviceCredentials` | Android | Allow PIN/pattern fallback |\n| `promptSubtitle` | Android | Subtitle for biometric prompt |\n| `promptDescription` | Android | Description for biometric prompt |\n| `cancelButtonText` | Android | Cancel button text |\n| `shouldMigrate` | iOS | Migrate from legacy keychain storage |\n\n\u003e **Note**: Decryption is not supported on Windows.\n\n- **Returns**: `Future\u003cDecryptResult\u003e`.\n  - `decryptedData`: The plaintext string.\n  - `code`: `BiometricError` code.\n\n```dart\nfinal result = await biometricSignature.decrypt(\n  payload: encryptedBase64,\n  payloadFormat: PayloadFormat.base64,\n  promptMessage: 'Authenticate to decrypt',\n  config: DecryptConfig(\n    allowDeviceCredentials: false,\n  ),\n);\n```\n\n### `deleteKeys()`\n\nDeletes all biometric key material (signing and decryption keys) from the device's secure storage.\n\n- **Returns**: `Future\u003cbool\u003e`.\n  - `true`: Keys were successfully deleted, or no keys existed (idempotent).\n  - `false`: Deletion failed due to a system error.\n\n\u003e **Note**: This operation is idempotent—calling `deleteKeys()` when no keys exist will still return `true`. This allows safe \"logout\" or \"reset\" flows without checking key existence first.\n\n```dart\nfinal deleted = await biometricSignature.deleteKeys();\nif (deleted) {\n  print('All biometric keys removed');\n}\n```\n\n\n### `biometricAuthAvailable()`\n\nChecks if biometric authentication is available on the device and returns a structured response.\n\n- **Returns**: `Future\u003cBiometricAvailability\u003e`.\n  - `canAuthenticate`: `bool` indicating if auth is possible.\n  - `hasEnrolledBiometrics`: `bool` indicating if user has enrolled biometrics.\n  - `availableBiometrics`: `List\u003cBiometricType\u003e` (e.g., `fingerprint`, `face`).\n  - `reason`: String explanation if unavailable.\n\n```dart\nfinal availability = await biometricSignature.biometricAuthAvailable();\nif (availability.canAuthenticate) {\n  print('Biometrics available: ${availability.availableBiometrics}');\n} else {\n  print('Not available: ${availability.reason}');\n}\n```\n\n### `getKeyInfo({ checkValidity, keyFormat })`\n\nRetrieves detailed information about existing biometric keys without prompting for authentication.\n\n- **Parameters**:\n  - `checkValidity`: Whether to verify the key hasn't been invalidated by biometric changes. Default is `false`.\n  - `keyFormat`: Output format for public keys (`KeyFormat.base64`, `pem`, `hex`). Default is `base64`.\n- **Returns**: `Future\u003cKeyInfo\u003e`.\n  - `exists`: Whether any biometric key exists.\n  - `isValid`: Key validity status (only populated when `checkValidity: true`).\n  - `algorithm`: `\"RSA\"` or `\"EC\"`.\n  - `keySize`: Key size in bits (e.g., 2048, 256).\n  - `isHybridMode`: Whether using hybrid signing/decryption keys.\n  - `publicKey`: The signing public key.\n  - `decryptingPublicKey`: Decryption key (hybrid mode only).\n\n```dart\nfinal info = await biometricSignature.getKeyInfo(\n  checkValidity: true,\n  keyFormat: KeyFormat.pem,\n);\n\nif (info.exists \u0026\u0026 (info.isValid ?? true)) {\n  print('Algorithm: ${info.algorithm}, Size: ${info.keySize}');\n  print('Hybrid Mode: ${info.isHybridMode}');\n}\n```\n\n### `biometricKeyExists({ checkValidity })`\n\nConvenience method that wraps `getKeyInfo()` and returns a simple boolean.\n\n- **Parameters**:\n  - `checkValidity`: Whether to check key validity. Default is `false`.\n- **Returns**: `Future\u003cbool\u003e` - `true` if key exists and is valid.\n\n```dart\nfinal exists = await biometricSignature.biometricKeyExists(checkValidity: true);\n```\n\n### `simplePrompt({ promptMessage, config })`\n\nPerforms biometric authentication without performing any cryptographic operation. Useful for quick re-authentication or gating sensitive UI.\n\n#### SimplePromptConfig Options\n\n| Option | Platforms | Description |\n|--------|-----------|-------------|\n| `subtitle` | Android | Subtitle for biometric prompt |\n| `description` | Android | Description for biometric prompt |\n| `cancelButtonText` | Android | Cancel button text |\n| `allowDeviceCredentials` | Android/iOS/macOS | Allow PIN/pattern/passcode fallback |\n| `biometricStrength` | Android | `BiometricStrength.strong` or `BiometricStrength.weak` |\n\n```dart\nfinal result = await biometricSignature.simplePrompt(\n  promptMessage: 'Verify your identity',\n  config: SimplePromptConfig(\n    subtitle: 'Access secure features',\n    allowDeviceCredentials: true,\n    biometricStrength: BiometricStrength.strong,\n  ),\n);\n\nif (result.success == true) {\n  // Authenticated\n} else {\n  print('Failed: ${result.code} - ${result.error}');\n}\n```\n\n---\n\n## Migration Guide\n\nThis section covers breaking changes and migration steps for upgrading between major versions. It assumes familiarity with the plugin’s core concepts (key creation, signing, biometric availability).\n\n### Migrating from v5/v6 to v7\n\n**v7.0.0** replaced the legacy map-based `createSignature()` API with typed `SignatureOptions`.\n\n#### `createSignature()` API Change\n\n**Before (v5/v6):**\n```dart\nfinal signature = await biometricSignature.createSignature(\n  options: {\n    'payload': 'data to sign',\n    'promptMessage': 'Authenticate',\n    'cancelButtonText': 'Cancel',          // Android\n    'allowDeviceCredentials': 'false',     // Android\n    'shouldMigrate': 'true',               // iOS\n  },\n);\n```\n\n**After (v7):**\n```dart\nfinal signature = await biometricSignature.createSignature(\n  SignatureOptions(\n    payload: 'data to sign',\n    promptMessage: 'Authenticate',\n    androidOptions: AndroidSignatureOptions(\n      cancelButtonText: 'Cancel',\n      allowDeviceCredentials: false,\n    ),\n    iosOptions: IosSignatureOptions(\n      shouldMigrate: true,\n    ),\n  ),\n);\n```\n\n\u003e [!NOTE]\n\u003e v7 provided a temporary helper `createSignatureFromLegacyOptions()` for migration, but this was removed in v8.\n\n---\n\n### Migrating from v7 to v8\n\n**v8.0.0** introduced structured return types and configurable key/signature formats.\n\n#### Return Types Changed\n\n**Before (v7):** Methods returned `String?` or `bool?`.\n\n**After (v8):** Methods return structured result objects with metadata.\n\n| Method | v7 Return Type | v8 Return Type |\n|--------|---------------|----------------|\n| `createKeys()` | `String?` | `KeyCreationResult?` |\n| `createSignature()` | `String?` | `SignatureResult?` |\n\n#### `createKeys()` Changes\n\n**Before (v7):**\n```dart\nfinal publicKey = await biometricSignature.createKeys(\n  androidConfig: AndroidConfig(useDeviceCredentials: false),\n  iosConfig: IosConfig(useDeviceCredentials: false),\n);\n// publicKey is a String?\n```\n\n**After (v8):**\n```dart\nfinal result = await biometricSignature.createKeys(\n  androidConfig: AndroidConfig(useDeviceCredentials: false),\n  iosConfig: IosConfig(useDeviceCredentials: false),\n  keyFormat: KeyFormat.pem,  // NEW: choose output format\n);\n// result.publicKey, result.algorithm, result.keySize available\n```\n\n#### `createSignature()` Changes\n\n**Before (v7):**\n```dart\nfinal signature = await biometricSignature.createSignature(options);\n// signature is a String?\n```\n\n**After (v8):**\n```dart\nfinal result = await biometricSignature.createSignature(\n  SignatureOptions(\n    payload: 'data',\n    promptMessage: 'Sign',\n    keyFormat: KeyFormat.base64,  // NEW: output format\n  ),\n);\n// result.signature, result.publicKey available\n```\n\n#### New Features in v8\n\n- **Key Formats:** `KeyFormat.base64`, `KeyFormat.pem`, `KeyFormat.hex`, `KeyFormat.raw`\n- **enforceBiometric:** Require biometric authentication during key creation\n- **setInvalidatedByBiometricEnrollment:** Bind keys to biometric enrollment state\n- **Decryption support (v8.4+):** RSA and ECIES decryption via `decrypt()`\n- **macOS support (v8.5):** Touch ID support on Mac via `MacosConfig`\n\n---\n\n### Migrating from v8 to v9\n\n**v9.0.0** is a major refactoring that unifies platform configurations and migrates to Pigeon for type-safe platform communication.\n\n#### Key Architecture Changes\n\n1. **Pigeon Migration:** All platform communication now uses strongly-typed Pigeon interfaces\n2. **Unified Config Objects:** Platform-specific configs (`AndroidConfig`, `IosConfig`, `MacosConfig`) consolidated into single config classes\n3. **Standardized Error Handling:** All methods return result objects with `BiometricError` enum codes\n4. **New Methods:** `getKeyInfo()` for detailed key inspection, `deleteKeys()` returns `Future\u003cbool\u003e`\n\n#### `createKeys()` Changes\n\n**Before (v8):**\n```dart\nfinal result = await biometricSignature.createKeys(\n  androidConfig: AndroidConfig(\n    useDeviceCredentials: false,\n    signatureType: AndroidSignatureType.RSA,\n    enforceBiometric: true,\n    setInvalidatedByBiometricEnrollment: true,\n    enableDecryption: true,\n  ),\n  iosConfig: IosConfig(\n    useDeviceCredentials: false,\n    signatureType: IOSSignatureType.RSA,\n    enforceBiometric: true,\n    setInvalidatedByBiometricEnrollment: true,\n  ),\n  macosConfig: MacosConfig(\n    useDeviceCredentials: false,\n    signatureType: MacosSignatureType.RSA,\n  ),\n  keyFormat: KeyFormat.pem,\n);\n```\n\n**After (v9):**\n```dart\nfinal result = await biometricSignature.createKeys(\n  keyFormat: KeyFormat.pem,\n  promptMessage: 'Authenticate to create keys',  // NEW: top-level\n  config: CreateKeysConfig(\n    signatureType: SignatureType.rsa,            // Unified enum\n    enforceBiometric: true,\n    setInvalidatedByBiometricEnrollment: true,\n    useDeviceCredentials: false,\n    enableDecryption: true,                      // Android only\n    promptSubtitle: 'Subtitle',                  // Android only\n    promptDescription: 'Description',            // Android only\n    cancelButtonText: 'Cancel',                  // Android only\n  ),\n);\n\nif (result.code == BiometricError.success) {\n  print('Public Key: ${result.publicKey}');\n} else {\n  print('Error: ${result.code} - ${result.error}');\n}\n```\n\n#### `createSignature()` Changes\n\n**Before (v8):**\n```dart\nfinal result = await biometricSignature.createSignature(\n  SignatureOptions(\n    payload: 'data to sign',\n    promptMessage: 'Authenticate',\n    keyFormat: KeyFormat.base64,\n    androidOptions: AndroidSignatureOptions(\n      cancelButtonText: 'Cancel',\n      allowDeviceCredentials: false,\n    ),\n    iosOptions: IosSignatureOptions(\n      shouldMigrate: true,\n    ),\n  ),\n);\n```\n\n**After (v9):**\n```dart\nfinal result = await biometricSignature.createSignature(\n  payload: 'data to sign',                        // Top-level parameter\n  promptMessage: 'Authenticate',                  // Top-level parameter\n  signatureFormat: SignatureFormat.base64,        // NEW: separate format\n  keyFormat: KeyFormat.base64,                    // Public key format\n  config: CreateSignatureConfig(\n    allowDeviceCredentials: false,                // Android\n    promptSubtitle: 'Subtitle',                   // Android\n    promptDescription: 'Description',             // Android\n    cancelButtonText: 'Cancel',                   // Android\n    shouldMigrate: true,                          // iOS\n  ),\n);\n\nif (result.code == BiometricError.success) {\n  print('Signature: ${result.signature}');\n}\n```\n\n#### `biometricAuthAvailable()` Changes\n\n**Before (v8):**\n```dart\nfinal availability = await biometricSignature.biometricAuthAvailable();\n// Returns String? like \"fingerprint\", \"face\", \"none\", etc.\n```\n\n**After (v9):**\n```dart\nfinal availability = await biometricSignature.biometricAuthAvailable();\n// Returns BiometricAvailability object\n\nif (availability.canAuthenticate ?? false) {\n  print('Biometrics available: ${availability.availableBiometrics}');\n  // availableBiometrics is List\u003cBiometricType\u003e\n} else {\n  print('Not available: ${availability.reason}');\n}\n```\n\n#### `decrypt()` Changes (v8.4+ → v9)\n\n**Before (v8):**\n```dart\nfinal result = await biometricSignature.decrypt(\n  DecryptionOptions(\n    payload: encryptedBase64,\n    promptMessage: 'Decrypt',\n    androidOptions: AndroidDecryptionOptions(\n      allowDeviceCredentials: false,\n    ),\n    iosOptions: IosDecryptionOptions(\n      shouldMigrate: true,\n    ),\n  ),\n);\n```\n\n**After (v9):**\n```dart\nfinal result = await biometricSignature.decrypt(\n  payload: encryptedBase64,\n  payloadFormat: PayloadFormat.base64,    // NEW: explicit format\n  promptMessage: 'Decrypt',\n  config: DecryptConfig(\n    allowDeviceCredentials: false,        // Android\n    shouldMigrate: true,                  // iOS\n  ),\n);\n\nif (result.code == BiometricError.success) {\n  print('Decrypted: ${result.decryptedData}');\n}\n```\n\n#### New `getKeyInfo()` Method\n\nv9 introduces `getKeyInfo()` for inspecting existing keys without authentication:\n\n```dart\nfinal info = await biometricSignature.getKeyInfo(\n  checkValidity: true,      // Check if key was invalidated\n  keyFormat: KeyFormat.pem,\n);\n\nif (info.exists ?? false) {\n  print('Algorithm: ${info.algorithm}');      // \"RSA\" or \"EC\"\n  print('Key Size: ${info.keySize}');         // 2048, 256, etc.\n  print('Hybrid Mode: ${info.isHybridMode}'); // Separate decrypt key?\n  print('Valid: ${info.isValid}');            // Not invalidated?\n}\n```\n\n\u003e [!TIP]\n\u003e `biometricKeyExists()` is now a convenience wrapper around `getKeyInfo()`.\n\n#### Summary of v9 Breaking Changes\n\n| Change | v8 | v9 |\n|--------|----|----|\n| Platform configs | `AndroidConfig`, `IosConfig`, `MacosConfig` | `CreateKeysConfig`, `CreateSignatureConfig`, `DecryptConfig` |\n| Signature type enum | `AndroidSignatureType.RSA` | `SignatureType.rsa` |\n| Error handling | Check for `null` | Check `result.code == BiometricError.success` |\n| biometricAuthAvailable | Returns `String?` | Returns `BiometricAvailability` |\n| Platform communication | MethodChannel with maps | Pigeon with typed classes |\n| Windows support | ❌ | ✅ (v9.0.0+) |\n\n#### Import Changes\n\n**Before (v8):**\n```dart\nimport 'package:biometric_signature/biometric_signature.dart';\nimport 'package:biometric_signature/android_config.dart';\nimport 'package:biometric_signature/ios_config.dart';\nimport 'package:biometric_signature/signature_options.dart';\n```\n\n**After (v9):**\n```dart\nimport 'package:biometric_signature/biometric_signature.dart';\n// All types exported from single import\n```\n\n### Migrating from v9 to v10\n\n**v10.0.0** refines error handling and introduces non-cryptographic authentication.\n\n#### Breaking: `BiometricError` Changes\n\n**Values Added**: New error codes were added to cover more edge cases:\n-   `BiometricError.securityUpdateRequired`\n-   `BiometricError.notSupported`\n-   `BiometricError.systemCanceled`\n-   `BiometricError.promptError`\n-   **Impact**: If you use exhaustive switch statements (e.g., in Dart 3.0+), you must add cases for these new values.\n\n#### New Feature: `simplePrompt()`\n\nv10 adds `simplePrompt()` for scenarios where you only need to verify the user's presence without cryptographic operations. See the [Usage](#usage) section for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchamodanethra%2Fbiometric_signature","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchamodanethra%2Fbiometric_signature","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchamodanethra%2Fbiometric_signature/lists"}