Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Tauri Plugin Secure Element
A Tauri plugin for secure element functionality on macOS & iOS (Secure Enclave) and Android (StrongBox and TEE).
Features
- Generate secure keys using hardware-backed secure storage
- Sign data with keys stored in secure elements
- List and manage secure keys
- Check secure element support on the device
- Support for biometric and PIN authentication modes
- Cross-platform support for macOS, Windows, iOS, and Android
Installation
npm
# or
# or
Cargo
[]
= "0.1.0-beta.3"
Setup
Add the plugin to your Rust code in src-tauri/src/lib.rs:
Add the plugin permissions to src-tauri/capabilities/default.json:
Android Biometrics
In order to use biometric protected keys, add this to src-tauri/gen/android/app/build.gradle.kts:
dependencies {
implementation("androidx.biometric:biometric:1.1.0")
}
Note: The src-tauri/gen/android folder is generated by Tauri but should be committed to version control and customized as needed. Once you add the biometric dependency, it will persist across builds (you only need to add it again if you completely regenerate the Android project with tauri android init).
iOS Face ID Permission
Important: For authentication-required keys to work on iOS with Face ID, you must add the Face ID usage description to your iOS Info.plist.
Add to src-tauri/gen/apple/tauri-app_iOS/Info.plist (replace tauri-app_iOS with your app name):
NSFaceIDUsageDescription
This app uses Face ID to authenticate access to your secure keys.
Add this entry anywhere within the <dict> section of the Info.plist file.
Note: Like the Android configuration, the src-tauri/gen/apple folder should be committed to version control. The Face ID permission will persist across builds unless you regenerate the iOS project with tauri ios init.
Touch ID does not require a separate permission entry - it works automatically when Face ID permission is granted or when no biometric hardware is available.
Usage
import {
checkSecureElementSupport,
generateSecureKey,
listKeys,
signWithKey,
deleteKey,
type AuthenticationMode,
type SecureElementBacking,
type SecureElementCapabilities,
} from "tauri-plugin-secure-element-api";
// Check device secure element capabilities
const capabilities = await checkSecureElementSupport();
console.log("Strongest backing:", capabilities.strongest);
console.log(
"Can enforce biometric-only:",
capabilities.canEnforceBiometricOnly
);
// Generate a new secure key
const { publicKey, keyName } = await generateSecureKey(
"my-key-name",
"pinOrBiometric" // or 'none' or 'biometricOnly'
);
// List all keys
const keys = await listKeys();
// Sign data with a key
const data = new Uint8Array([1, 2, 3, 4]);
const signature = await signWithKey("my-key-name", data);
// Delete a key
await deleteKey("my-key-name");
API Reference
checkSecureElementSupport()
Returns detailed information about secure element hardware capabilities on the device.
Returns: Promise<SecureElementCapabilities>
/**
* Hardware backing tiers, ordered weakest → strongest:
* "none" < "firmware" < "integrated" < "discrete"
*/
type SecureElementBacking = "none" | "firmware" | "integrated" | "discrete";
interface SecureElementCapabilities {
/** A discrete physical security chip is available (e.g. discrete TPM 2.0, macOS T2, Android StrongBox) */
discrete: boolean;
/** An on-die isolated security core is available (e.g. Apple Silicon Secure Enclave, ARM TrustZone/TEE) */
integrated: boolean;
/** Firmware-backed security is available but no dedicated secure processor (e.g. Windows fTPM via Intel PTT or AMD PSP) */
firmware: boolean;
/** The security is emulated/virtual (e.g. vTPM in a VM, iOS Simulator, Android Emulator) */
emulated: boolean;
/** The strongest hardware backing tier available on this device */
strongest: SecureElementBacking;
/** Whether biometric-only authentication can be enforced at the key level (Android API 30+ only) */
canEnforceBiometricOnly: boolean;
}
Hardware Backing Tiers:
| Tier | Description | Examples |
|---|---|---|
none |
No secure element available (software-only) | Unsupported devices, some VMs |
firmware |
Firmware-backed, no dedicated secure processor | Windows fTPM (Intel PTT, AMD PSP) |
integrated |
On-die isolated security core | Apple Silicon Secure Enclave, ARM TrustZone/TEE |
discrete |
Physically separate security processor | Discrete TPM 2.0, macOS T2 chip, Android StrongBox |
Usage Example:
const caps = await checkSecureElementSupport();
// Check if any hardware backing is available
if (caps.strongest === "none") {
console.warn("No secure element available - keys will be software-only");
}
// Check for high-security backing (discrete or integrated)
if (caps.strongest === "discrete" || caps.strongest === "integrated") {
console.log("High-security hardware backing available");
}
// Warn if running in emulated environment
if (caps.emulated) {
console.warn("Running in emulator/VM - security may be reduced");
}
// Check before creating biometric-only keys
if (caps.canEnforceBiometricOnly) {
await generateSecureKey("my-key", "biometricOnly");
}
generateSecureKey(keyName: string, authMode?: AuthenticationMode)
Generates a new secure key in the device's secure element.
Parameters:
keyName: Unique name for the keyauthMode: Authentication mode ('none','pinOrBiometric', or'biometricOnly')
Returns: Promise<GenerateSecureKeyResult>
interface GenerateSecureKeyResult {
publicKey: string;
keyName: string;
hardwareBacking: "secureEnclave" | "strongBox" | "tee";
}
Note: The biometricOnly mode requires Android 11 (API 30) or higher. On older Android versions, this mode will be rejected with an error. Use checkSecureElementSupport().canEnforceBiometricOnly to check support before creating biometric-only keys.
listKeys(keyName?: string, publicKey?: string)
Lists keys stored in the secure element. Can filter by key name or public key.
Returns: Promise<KeyInfo[]>
interface KeyInfo {
keyName: string;
publicKey: string;
}
signWithKey(keyName: string, data: Uint8Array)
Signs data using a key stored in the secure element.
Parameters:
keyName: Name of the key to usedata: Raw data to sign asUint8Array(do not pre-hash)
Returns: Promise<Uint8Array> - DER-encoded ECDSA signature
Important: The plugin automatically hashes your data with SHA-256 before signing. Pass raw data, not a pre-computed hash. See Signature Format for details.
deleteKey(keyName?: string, publicKey?: string)
Deletes a key from the secure element. At least one parameter must be provided.
Returns: Promise<boolean> - Success status
Public Key Format
Public keys are returned as base64-encoded strings in X9.62 uncompressed point format (65 bytes), consistent across all platforms:
| Byte(s) | Content |
|---|---|
| 0 | 0x04 (uncompressed) |
| 1-32 | X coordinate (32 bytes) |
| 33-64 | Y coordinate (32 bytes) |
All keys use the secp256r1 (P-256) elliptic curve.
Signature Format
Hashing Convention
The plugin automatically hashes your data with SHA-256 before signing. This is handled internally on all platforms:
- iOS/macOS: Hashes data, then signs with
.ecdsaSignatureDigestX962SHA256 - Android: Uses
SHA256withECDSAwhich hashes internally - Windows: Explicitly hashes with SHA-256 before calling
NCryptSignHash
Do not pre-hash your data. Pass the raw data to signWithKey() and the plugin handles hashing.
Signature Output
Signatures are returned as DER-encoded ECDSA signatures (ASN.1 format), consistent across all platforms. Typical size is 70-72 bytes for P-256.
SEQUENCE {
INTEGER r, -- 32-33 bytes (may have leading 0x00 for sign bit)
INTEGER s -- 32-33 bytes (may have leading 0x00 for sign bit)
}
Verifying Signatures
To verify a signature produced by this plugin:
- Use the raw original data (not hashed)
- Use an ECDSA-SHA256 verification algorithm (the verifier will hash internally)
- Use the secp256r1 (P-256) curve
- The signature is DER-encoded
Example (Node.js):
import { createVerify } from "crypto";
function verifySignature(
publicKeyBase64: string,
data: Uint8Array,
signatureDer: Uint8Array
): boolean {
// Convert X9.62 public key to PEM format
const publicKeyBuffer = Buffer.from(publicKeyBase64, "base64");
const publicKey = {
key: publicKeyBuffer,
format: "raw",
type: "spki",
namedCurve: "P-256",
};
const verify = createVerify("SHA256");
verify.update(data); // Pass raw data - verify() hashes internally
return verify.verify(
{ key: publicKey, dsaEncoding: "der" },
Buffer.from(signatureDer)
);
}
Example (Web Crypto API):
async function verifySignature(
publicKeyBase64: string,
data: Uint8Array,
signatureDer: Uint8Array
): Promise<boolean> {
const publicKeyBytes = Uint8Array.from(atob(publicKeyBase64), (c) =>
c.charCodeAt(0)
);
// Import the raw public key
const publicKey = await crypto.subtle.importKey(
"raw",
publicKeyBytes,
{ name: "ECDSA", namedCurve: "P-256" },
false,
["verify"]
);
// Note: Web Crypto expects raw R||S format, not DER
// You may need to convert DER to raw format (64 bytes)
const signatureRaw = derToRaw(signatureDer);
return crypto.subtle.verify(
{ name: "ECDSA", hash: "SHA-256" },
publicKey,
signatureRaw,
data // Pass raw data - verify() hashes internally
);
}
Platform Support
- iOS: Uses Secure Enclave for key generation and signing
- Android: Uses StrongBox and TEE (Trusted Execution Environment) when available
- Windows: Uses TPM 2.0 for key generation and signing
- macOS: Uses Secure Enclave for key generation and signing
Platform Limitations
Windows
- Windows 11 (build 22000 or higher) requires TPM 2.0
- TPM 2.0 is supported on Windows 10 (since version 1507)
macOS
- Secure Enclave is available on Macs with Apple Silicon (M1/M2/M3/M4) or T2 chip
Android
| Feature | Requirement | Notes |
|---|---|---|
| Hardware-backed keys | API 23+ | TEE or StrongBox required |
| StrongBox | API 28+ | Falls back to TEE if unavailable |
biometricOnly auth mode |
API 30+ | Rejected on older versions |
iOS
- Secure Enclave is available on all devices with A7 chip or later (iPhone 5s+)
- Simulator does not support Secure Enclave - test on physical devices
Authentication Modes
| Mode | iOS/MacOS | Android | Windows |
|---|---|---|---|
none |
✅ No auth required | ✅ No auth required | ✅ No auth required |
pinOrBiometric |
✅ Face ID, Touch ID, or passcode | ✅ Biometric or PIN/pattern/password | ✅ Windows Hello |
biometricOnly |
❌ Not supported | ✅ API 30+ only, biometric only | ❌ Not supported |
License
Apache-2.0
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.