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:

  • mousemove
  • mousedown
  • keydown
  • touchstart
  • scroll

Any of these events resets the idle timer. When the timer expires:

  1. Lock the wallet (zero out all in-memory seeds)
  2. Stop the auto-receive poller
  3. Clear application state
  4. 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