Wallet Security
Wallet Security
This page details the cryptographic storage, session management, and encoding compatibility mechanisms used by the XE web wallet.
Seed encryption
Private keys (seeds) are encrypted at rest using AES-GCM with PBKDF2-derived keys.
Key derivation
Parameter
Value
Algorithm
PBKDF2
Hash
SHA-256
Iterations
100,000
Key length
256 bits
Salt
Random, per wallet
The user's passphrase is fed through PBKDF2 to produce a 256-bit AES key. Each wallet has its own random salt, so the same passphrase produces different keys for different wallets.
Encryption
Parameter
Value
Algorithm
AES-GCM
IV
Random, per encryption
Input
32-byte hex seed
Output
Base64-encoded ciphertext
A fresh random IV is generated every time a seed is encrypted (on wallet creation, import, or passphrase change). This ensures that re-encrypting the same seed produces different ciphertext.
[!IMPORTANT] Important The IV must be unique per encryption. Reusing an IV with the same key completely breaks AES-GCM's security guarantees.
Storage schema
Wallet data is stored in localStorage as a JSON object:
{
"version": 1,
"activeId": "w_1709123456789",
"wallets": [
{
"id": "w_1709123456789",
"name": "default",
"encrypted": "<base64 ciphertext>",
"salt": "<base64 salt>",
"iv": "<base64 IV>"
}
]
}Field
Description
version
Schema version (currently 1)
activeId
ID of the currently selected wallet
wallets[]
Array of wallet entries
wallets[].id
Unique ID (w_ + creation timestamp)
wallets[].name
User-assigned display name
wallets[].encrypted
Base64-encoded AES-GCM ciphertext of the seed
wallets[].salt
Base64-encoded PBKDF2 salt
wallets[].iv
Base64-encoded AES-GCM initialization vector
[!NOTE] Note No plaintext seed or private key is ever written to
localStorage. Only the encrypted ciphertext, salt, and IV are persisted.
Session management
Idle timeout
The wallet automatically locks after 5 minutes (300,000 ms) of inactivity.
Monitored events:
mousemovemousedownkeydowntouchstartscroll
Any of these events resets the idle timer. When the timer expires:
- Lock the wallet (zero out all in-memory seeds)
- Stop the auto-receive poller
- Clear application state
- Redirect to the unlock screen
Lock behavior
When locked, all decrypted seeds are overwritten with zeros and dereferenced. The wallet transitions to a state where only the unlock form is accessible. Re-entering the passphrase decrypts all wallet seeds and resumes normal operation.
Key operations
Operation
Description
Unlock
Decrypt all wallet seeds using the passphrase. Derives AES keys via PBKDF2, decrypts each seed with AES-GCM.
Lock
Zero out all in-memory seeds, stop poller, clear state.
Add wallet
Generate or import a seed, encrypt with current passphrase, store in localStorage.
Remove wallet
Delete a wallet entry from localStorage. Requires at least one wallet to remain.
Rename wallet
Update the name field in localStorage.
Reveal seed
Re-authenticate with passphrase, then display the decrypted seed.
Change passphrase
Re-encrypt all wallet seeds with a new passphrase. Generates new salts and IVs.
[!WARNING] Passphrase change Changing the passphrase re-encrypts every wallet seed with fresh salt and IV. If the process is interrupted (e.g., browser crash), some wallets may be encrypted with the old passphrase and some with the new. The wallet handles this gracefully by attempting both on unlock.
Canonical encoding compatibility
The wallet must produce byte-identical canonical block encodings to the Go node for hashing and signing to work correctly. The JavaScript implementation mirrors the Go MarshalBlockCanonical function exactly:
Constant
Value
Shared between Go and JS
VERSION_BYTE
0x02
Yes
Send type
0x01
Yes
Receive type
0x02
Yes
Claim type
0x03
Yes
Lease type
0x04
Yes
LeaseAccept type
0x05
Yes
LeaseSettle type
0x06
Yes
Field ordering, padding, and endianness are identical. See Binary Encoding for the full specification.
See also
- Wallet Overview -- feature summary and tech stack
- Wallet Features -- detailed feature reference
- Cryptography -- ed25519 and hashing primitives
- Binary Encoding -- canonical block encoding