eID Wallet
The eID Wallet is a mobile application that manages cryptographic keys, authenticates users with platforms, and provides the user interface for eVault creation and management.
Overview
The eID Wallet is a Tauri-based mobile application (built with SvelteKit and TypeScript) that serves as the primary interface for users in the W3DS ecosystem. It uses secure cryptographic enclaves on modern mobile devices to store and manage private keys without exposing them.
Key Features
- Key Management: Generate and manage ECDSA P-256 key pairs
- Hardware Security: Uses device cryptographic enclaves (Secure Enclave on iOS, Hardware Security Module on Android)
- eVault Creation: User interface for provisioning a new eVault (one eVault per user)
- Platform Authentication: Sign session IDs for platform login
- Signature Creation: Sign arbitrary payloads for various use cases
- Key Rotation: Planned feature for rotating keys in case of security incidents (not yet implemented)
- Multi-Device Support: Keys can be synced across devices. See eVault Key Delegation for details on how multiple devices link to the same eName.
Architecture
Key Management
The eID Wallet manages cryptographic keys through a flexible key manager system.
Key Manager Types
Hardware Key Manager
Uses device-native cryptographic APIs:
- iOS: Secure Enclave via LocalAuthentication framework
- Android: Hardware Security Module (HSM) via KeyStore API
- Benefits: Private keys never leave the secure hardware
- Limitations: Device-specific, cannot export keys
Software Key Manager
Uses Web Crypto API:
- Storage: Keys stored in browser's secure storage
- Benefits: Works on all platforms, can be exported
- Limitations: Less secure than hardware keys
Key Manager Selection
The wallet automatically selects the appropriate key manager:
- Pre-verification Mode: Always uses software keys (for testing/fake users only)
- Real KYC/Verification: Always uses hardware keys (never software keys)
- Hardware Available: Requires hardware keys; onboarding is blocked if hardware keys are unavailable (no software fallback)
- Explicit Request: Can force hardware or software based on configuration (for non-onboarding operations)
Key Operations
Generate Key
Generate a new ECDSA P-256 key pair:
Process:
- Determine key manager (hardware or software)
- Generate key pair using appropriate API
- Store key identifier (not the private key itself)
- Return public key
Implementation:
- Hardware: Uses device-native key generation
- Software: Uses
crypto.subtle.generateKey()with ECDSA P-256 parameters
Get Public Key
Retrieve the public key for a given key ID:
Process:
- Load key manager for the key ID
- Extract public key from key pair
- Encode as multibase format
- Return public key string
Format: Multibase-encoded (starts with 'z' for base58btc or 'm' for base64)
Sign Payload
Sign a string payload with a private key:
Process:
- Convert payload string to UTF-8 bytes
- Compute SHA-256 hash
- Sign hash with ECDSA P-256
- Encode signature (base64 for software, multibase for hardware)
- Return signature string
Algorithm: ECDSA P-256 with SHA-256
Signature Format:
- Software keys: Base64-encoded 64-byte raw signature
- Hardware keys: Multibase base58btc-encoded signature
Verify Signature
Verify a signature against a payload (for testing):
Process:
- Get public key for key ID
- Decode signature
- Hash payload with SHA-256
- Verify signature using ECDSA P-256
- Return boolean result
User Journeys
Onboarding and eVault Creation
When a new user first opens the wallet:
- Generate Keys: Create default key pair (hardware keys for real users, software keys only for pre-verification/test users)
- Request Entropy: Get entropy token from Registry
- Generate Namespace: Create a unique identifier for namespace
- Provision eVault: Send provision request with public key to the Provisioner service (not to eVault Core, as no eVault exists yet, and not to Registry)
- Receive Credentials: Get W3ID (eName) and eVault URI
- Store Locally: Save credentials in wallet storage
API Flow (see Registry for entropy and key binding):
Wallet → Registry: GET /entropy
Registry → Wallet: JWT entropy token
Wallet → Provisioner: POST /provision (entropy, namespace, publicKey)
Provisioner → Registry: Request key binding certificate
Registry → Provisioner: JWT certificate
Provisioner → Wallet: w3id, evaultUri
Note: The /provision endpoint is part of the Provisioner service, not eVault Core. This is the provisioning protocol - any vault provider should expose such an endpoint to enable eVault creation.
Platform Authentication
User authenticating their eName to a platform:
When a user wants to log into a platform:
- Scan QR Code: Platform displays QR code with
w3ds://authURI in the format:w3ds://auth?redirect={url}&session={sessionId}&platform={platformName} - Parse URI: Extract
session(session ID) andredirect(redirect URL) from the URI query parameters - Sign Session: Sign session ID with default key
- Send to Platform: POST signed session to platform's
/api/auth/loginendpoint (theredirectURL from step 2) - Receive Token: Platform verifies signature and returns auth token
For detailed information on:
- Signature verification flow: See Signing documentation for the complete verification process (including Registry resolution, eVault
/whoisendpoint, and JWT certificate verification) - Auth token generation: See Authentication documentation for how platforms generate authentication tokens after signature verification
Signing Details:
- Uses key ID
"default" - Uses context
"onboarding"for real users (always hardware keys) or"pre-verification"for fake/test users (software keys) - For real KYC-verified users: Always uses hardware keys, never software keys
- Signs the exact session ID string
- Returns base64 or multibase-encoded signature
Key Rotation (Conceptual - Not Yet Implemented)
Key rotation is a planned feature that would allow users to rotate their keys in case of security incidents or device loss. The concept would involve:
- Generate New Key: Create new key pair
- Sync to eVault: Send new public key to eVault
- Update Certificates: eVault requests new key binding certificate
- Revoke Old Key: Optionally revoke old key (if supported)
Note: The W3ID (eName) would remain the same - only the keys would change. This feature is on the roadmap but not currently implemented.
Public Key Syncing
Public keys must be synced to eVault so platforms can verify signatures.
Sync Process
- Get Public Key: Retrieve public key from key manager
- Format: Ensure public key is in multibase format
- Send to eVault: POST to eVault's key storage endpoint
- Certificate Generation: eVault requests key binding certificate from Registry
- Storage: Certificate stored in eVault for future verification
Sync Timing
- During Provisioning: Public key included in
/provisionrequest - Multi-Device: Each device syncs its own public key (see eVault Key Delegation for details)
Signature Creation
The wallet creates signatures for various purposes:
Authentication Signatures
Purpose: Prove identity to platforms
Payload: Session ID (string)
Process:
- Platform generates session ID
- Wallet receives session ID via
w3ds://authURI - Wallet signs session ID with default key
- Wallet sends signature to platform
Document Signatures
Purpose: Sign documents, contracts, or other data
Payload: Arbitrary string (document hash, JSON, etc.)
Process:
- User initiates signing action
- Wallet receives payload to sign
- Wallet signs payload with appropriate key
- Wallet returns signature to application
Voting Signatures
Purpose: Sign votes in voting systems
Payload: Vote session ID or vote data
Process: Similar to document signatures, but with vote-specific payloads
Security Considerations
Private Key Protection
- Hardware Keys: Private keys never leave secure hardware
- Software Keys: Stored in browser's secure storage (encrypted at rest)
- No Export: Private keys cannot be exported (security requirement)
- Biometric Protection: Hardware keys require biometric authentication
Multi-Device Support
- Per-Device Keys: Each device has its own key pair
- Multiple Certificates: eVault can store multiple key binding certificates
- Verification: Platforms try all certificates until one succeeds
Implementation Details
Technology Stack
- Framework: Tauri (Rust + Web frontend)
- Frontend: SvelteKit + TypeScript
- Key APIs:
- iOS: LocalAuthentication (Secure Enclave)
- Android: KeyStore (HSM)
- Web: Web Crypto API
Key Service Architecture
KeyService
├── KeyManagerFactory
│ ├── HardwareKeyManager
│ └── SoftwareKeyManager
├── Key Storage (encrypted)
└── Context Management
Key Manager Interface
All key managers implement:
interface KeyManager {
exists(keyId: string): Promise<boolean>;
generate(keyId: string): Promise<string | undefined>;
getPublicKey(keyId: string): Promise<string | undefined>;
signPayload(keyId: string, payload: string): Promise<string>;
verifySignature(keyId: string, payload: string, signature: string): Promise<boolean>;
getType(): "hardware" | "software";
}
API Integration
eVault Provisioning
// Request entropy from Registry
const entropyResponse = await fetch(`${registryUrl}/entropy`);
const entropyToken = await entropyResponse.json();
// Generate namespace
const namespace = uuidv4();
// Provision eVault with public key
// Note: Real users always use hardware keys (context: "onboarding")
// Pre-verification/test users use software keys (context: "pre-verification")
const publicKey = await keyService.getPublicKey("default", "onboarding");
const provisionResponse = await fetch(`${provisionerUrl}/provision`, {
method: "POST",
body: JSON.stringify({
registryEntropy: entropyToken,
namespace: namespace,
verificationId: verificationCode,
publicKey: publicKey
})
});
const { w3id, uri } = await provisionResponse.json();
Note: The /provision endpoint is hosted by the Provisioner service, not eVault Core.
Platform Authentication
// Parse w3ds://auth URI
const uri = new URL(authUri);
const sessionId = uri.searchParams.get("session");
const redirectUrl = uri.searchParams.get("redirect");
// Sign session ID
const signature = await keyService.signPayload(
"default",
"onboarding",
sessionId
);
// Send to platform
const response = await fetch(redirectUrl, {
method: "POST",
body: JSON.stringify({
w3id: vault.ename,
session: sessionId,
signature: signature,
appVersion: "0.4.0"
})
});
const { token } = await response.json();
Troubleshooting
Common Issues
-
Hardware keys not available
- Check device support (iOS 9+, Android 6+)
- Verify biometric authentication is set up
- Note: Real KYC-verified users must use hardware keys. Software keys are only for pre-verification/test users
- Onboarding requirement: The eID Wallet enforces hardware key manager during onboarding. Onboarding cannot proceed without hardware keys - there is no fallback to software keys for real users
-
Signature verification fails
- Ensure using correct key ID and context
- Verify public key was synced to eVault
- Check signature encoding format
-
Key generation fails
- Check device storage space
- Verify cryptographic APIs are available
- For real users: Hardware key generation must succeed (software fallback not acceptable)
- For pre-verification/test users: Software key manager can be used as fallback
References
- Registry - Entropy and key binding certificates
- W3ID - Identifiers and eName resolution
- Links - Production URLs (Provisioner, Registry, Ontology)
- Authentication - How wallet authentication works
- Signing - Signature creation details
- Signature Formats - Technical signature format details
- eVault - Where public keys are stored