Introducing Seed Vault: Secure On-Chain Seed Phrase Storage with vetKeys on ICP

Introducing Seed Vault: Secure On-Chain Seed Phrase Storage with vetKeys on ICP

Hey everyone in the ICP community,

I’m excited to share a project I’ve been working on called Seed Vault – a simple, secure app deployed on the Internet Computer Protocol (ICP) blockchain that lets users encrypt and store their seed phrases online using vetKeys. I know what you’re thinking: “Storing seed phrases online? That’s a big no-no!” And you’re absolutely right – in most cases, it’s a terrible idea due to the risks of hacks, leaks, or centralized vulnerabilities. But with ICP’s vetKeys technology, this app demonstrates how you could theoretically do it safely in a decentralized way, without ever exposing your plaintext seeds to the backend or anyone else. Of course, I’d still recommend air-gapped hardware wallets for your most critical assets, but Seed Vault shows off some cool ICP features for secure, encrypted storage.

The app is live and fully functional, so feel free to check it out, test it, or even deploy your own instance. I’ll dive into the details below.

Live Demo and Repo

If you’re new to vetKeys, it’s ICP’s verifiably encrypted threshold key derivation system – basically, it allows canisters to derive encrypted keys on-demand in a distributed, secure manner without a single point of failure. For more on vetKeys, check out the official docs or the encrypted notes tutorial that inspired parts of this project.

What Does Seed Vault Do?

Seed Vault is a basic web app that lets you:

  • Authenticate via Internet Identity (II) for seamless, secure login.
  • Store multiple seed phrases (or passwords) under custom titles, encrypted on-chain using vetKeys and AES-GCM.
  • View a list of your stored seed titles without decrypting anything (no cost or exposure).
  • Decrypt individual seeds on-demand by clicking a button next to the title – but only after confirming the billing cost.
  • Automatically hide and clear decrypted seeds from memory after 5 minutes for added security.
  • Transfer ICP out of your subaccount if needed.

Here’s a quick walkthrough of the user flow:

  1. Login: Use Internet Identity to authenticate. No passwords, just your ICP principal.
  2. Add a Seed: Enter a title (e.g., “My Ledger Wallet”) and your seed phrase. The app derives a unique vetKey for encryption, encrypts locally in your browser, and stores the ciphertext on the backend canister.
  3. View List: See all your seed titles in a list. No decryption happens here – it’s free and safe.
  4. Decrypt a Seed: Click “Decrypt” next to a title. You’ll get a confirmation prompt with the exact ICP cost (dynamically calculated). After paying, the app fetches the ciphertext, derives the decryption key via vetKeys, and shows the plaintext temporarily.
  5. Billing Confirmation: Before any paid operation (encrypt/decrypt), a popup shows the cost in ICP, how much you’ll be billed, and asks for confirmation. This prevents surprises.
  6. Auto-Top-Up: Collected ICP fees are automatically converted to cycles to keep the backend canister running indefinitely.

The app enforces limits like 420 characters per seed, 100 characters per title, and 50 seeds per user to keep things efficient and secure.

Key Features and Unique Setup

What makes Seed Vault stand out is how it leverages ICP’s native capabilities for security and sustainability:

1. vetKeys Integration for Secure Encryption

  • Each seed is encrypted using a unique symmetric key derived from vetKeys. The key is generated on-demand via ICP’s threshold key derivation, meaning no single node holds the master key – it’s distributed across the subnet.
  • Encryption happens client-side in your browser using AES-GCM (with a random IV for each seed).
  • Decryption also stays client-side: The backend only stores ciphertext and never sees plaintext or keys.
  • This setup ensures that even if the canister is compromised (unlikely on ICP), your seeds remain encrypted. vetKeys’ verifiability adds an extra layer, proving the derived keys are correct without trusting a central authority.
  • Inspired by the encrypted notes tutorial, but extended for seed phrases with dynamic billing.

2. Dynamic Pricing and Auto-Top-Up

  • Operations like encrypting/decrypting cost cycles, which are billed in ICP via dynamic exchange rates from the XRC canister (ICP/XDR rates refreshed every 5 minutes).
  • If live rates fail (e.g., due to network issues), it falls back to cached or hardcoded estimates to keep the app running smoothly.
  • Users are charged exactly for what they use: ~0.0001 ICP ledger fee + a small buffer for cycles. No subscriptions – pay per operation.
  • Collected ICP is automatically converted to cycles via the Cycles Minting Canister (CMC) and withdrawn from the cycles ledger. This “auto-top-up” keeps the backend canister funded forever without manual intervention.
  • Pricing includes safety caps (e.g., max 1 ICP per op) and rate deviation checks to prevent overcharges.

3. Security-Focused UX

  • Individual Decryption: Only decrypt what you need, when you need it. The list view is free and doesn’t expose anything.
  • Billing Popups: Before charging, a popup confirms the exact cost and requires user approval. For decryption, it warns about trusted devices.
  • Auto-Clear: Decrypted seeds are stored in sessionStorage and cleared after 5 minutes (with a countdown). They’re also hidden by default.
  • Rate Limiting: 20 ops/hour per user, 200 global, to prevent abuse.
  • Audit Logs: A short history of your actions (e.g., “Added seed X”) is available.
  • Content-Security-Policy: Hardened headers in ic-assets.json5 to mitigate XSS.
  • No Plaintext Storage: Backend only holds encrypted blobs; keys are derived fresh each time.

Seed Vault proves you could safely store backups or less-critical phrases online on ICP without trusting a centralized service. Everything’s decentralized, encrypted, and verifiable.

Tech Stack

  • Backend: Motoko canister handling storage, vetKeys derivation, ICP ledger transfers, and cycle conversions.
  • Frontend: React app with AuthClient for II login, CryptoJS for AES-GCM fallback (WebCrypto primary), and vetKeys library for key handling.
  • Deployment: dfx for local dev; deployed on mainnet with custom canister IDs.
  • Dependencies: @dfinity/agent, @dfinity/vetkeys, crypto-js, etc.

The code is open-source – feel free to audit, fork, or contribute. It’s a great starting point if you’re building encrypted apps on ICP.

Limitations and Warnings

  • Not for Production Secrets: This is a demo/proof-of-concept. Always back up seeds offline.
  • Costs Fluctuate: ICP prices change with exchange rates – check the app’s pricing status.
  • Browser Security: Decryption happens in-browser, so use on trusted devices only. Mobile Safari may have quirks with popups.
  • No Recovery: If you lose your II, your seeds are gone (by design for security).
  • Test Thoroughly: I’ve tested on mainnet, but always use small amounts first.

Feedback and Next Steps

I’d love your thoughts! Does this spark ideas for vetKeys use cases? Any bugs, suggestions, or improvements?

Thanks for checking it out – let’s build more secure dApps on ICP! :rocket:

11 Likes

Update: New Features in Seed Vault – Images, Encrypted Data Views, and More!

I’ve been iterating on the app and have introduced some new updates. The latest version (check out this commit for a fully functional build with the updates) adds some cool new capabilities while keeping the core focus on secure, on-demand encryption/decryption.

Here’s what’s new:

1. Attach Encrypted Images to Your Seeds

  • You can now upload and attach an image (e.g., a QR code, wallet screenshot, or mnemonic diagram) to each seed phrase.
  • Images are encrypted client-side using the same vetKey-derived AES-GCM key as the seed phrase itself (max 1MB file size).
  • When adding a seed, there’s an optional file input for images. Existing seeds without images show an “Add image” button.
  • Decryption handles both the seed and image in one go – no extra steps or costs beyond the standard derivation/decrypt fee.
  • UI previews: Decrypted images show as thumbnails with click-to-enlarge for better usability.

This extends Seed Vault beyond just text seeds, making it more versatile for storing visual backups or related artifacts securely on-chain.

2. View Raw Encrypted Data On-Chain

  • For transparency and auditing, you can now toggle a “Show encrypted” view for any decrypted seed.
  • This displays the base64-encoded ciphertext (cipher) and initialization vector (IV) for the seed phrase and attached image (if any).
  • No extra cost – it’s fetched during decryption and shown in a scrollable panel.
  • Great for verifying that data is indeed encrypted at rest, or for advanced users who want to inspect the on-chain blobs without trusting the frontend.

3. Improved UI and Security Tweaks

  • Image Handling UX: Previews for selected images before upload, enlarged modal views, and automatic URL revocation for decrypted blobs to prevent memory leaks.
  • Better Validation: Stricter client-side checks for seed names (no leading/trailing hyphens/underscores, etc.) to match backend rules and reduce errors.
  • Fallback Pricing Notice: If live ICP/XDR rates from XRC fail, the app now clearly warns about using cached/fallback estimates and encourages refreshing before paying.
  • Rate Limiting Grace: Slightly loosened limits (now 400 ops/5 min per user, 4000 global) to handle bursts like adding images or decrypting multiple seeds without spurious rejections.
  • Safari Compatibility: Adjusted login flow for better popup handling on iOS Safari.

The app still follows the same pay-per-op model with dynamic billing, client-side crypto, and auto-clear after 5 minutes. No changes to the core vetKeys/AES-GCM workflow – these additions just build on it to show more real-world use cases.

As always, this is a proof-of-concept – use hardware wallets for critical seeds! I’d love feedback on the new image support or encrypted views.

1 Like