u/Economy_Hamster_8645

** [veil-cli #2] Ethereum keystore v3 with zero new dependencies — just node:crypto **
▲ 1 r/ethdev

** [veil-cli #2] Ethereum keystore v3 with zero new dependencies — just node:crypto **

Previously: veil-cli #1 — decode, simulate, risk before you sign


When you're building a security tool, every dependency becomes part of your threat model.

That's why we implemented Ethereum keystore v3 using only node:crypto and dependencies we already had.

What keystore v3 actually is

The format used by geth, MetaMask, and MyCrypto is straightforward:

  1. Derive a key from your password using scrypt
  2. Encrypt the private key with AES-128-CTR using the first 16 bytes of the derived key
  3. Compute a MAC over the last 16 bytes + ciphertext to detect wrong passwords on decryption

Everything needed is in node:crypto — except the MAC, which uses keccak256. We already had viem as a dependency, so we pulled keccak256 from there. No new packages.

One implementation detail surprised me

crypto.scryptSync() with N=131072 blocks the event loop for ~1–2 seconds.

For a CLI that's technically acceptable, but we switched to the async version anyway — and had to raise maxmem to 160MB because the Node default of 32MB isn't enough for these parameters. That one caught us off guard.

One thing that's probably overkill

The MAC comparison uses crypto.timingSafeEqual() instead of a plain string comparison.

Is a timing attack against a local CLI keystore a realistic threat? Probably not.

But if you're writing a security tool, it's hard to justify doing it the wrong way.

Result

veil wallet create — generates a key, asks for a password with confirmation, writes an encrypted .json to ~/.veil/wallets/<name>.json with 0o600 permissions.

veil wallet import — same flow, bring your own private key.

veil wallet list — shows all wallets and their addresses.

The output is a standard keystore v3 file — importable into MetaMask or any client that supports the format.


One thing I'm still debating:

Should a security-focused CLI store encrypted private keys at all, or should it only integrate with external signers (hardware wallets, browser extensions)?

Curious how others have approached that tradeoff.

Repo: github link

u/Economy_Hamster_8645 — 10 days ago
▲ 3 r/ethdev

veil — terminal-first tool that decodes, simulates, and risk-checks EVM transactions before you sign

I've been building veil-cli — an open-source, terminal-first security tool for EVM users.

The goal is simple: before signing a transaction, you should be able to understand what it actually does.

Unlike Etherscan or Tenderly, veil runs locally, requires no browser, and chains decode → simulate → risk into one CLI flow.

Current MVP features:

  • veil decode <tx-hash|calldata> Decodes calldata into a human-readable function call. ABI resolution flow: Etherscan → Sourcify → 4byte.directory fallback

  • veil approvals <address> Scans active ERC-20 / ERC-721 approvals from event logs and flags unlimited (MaxUint256) allowances

  • veil simulate <tx.json|tx-hash> Forks the chain locally with Anvil, executes the transaction, and shows balance diffs before broadcasting

  • veil risk <address> Runs on-chain heuristics (proxy detection, bytecode checks, EOA detection, etc.) alongside GoPlus Security API checks and returns a risk report with flags

  • veil explain <address> Interactive Ink TUI for exploring the risk report — drill down into each flag with context and on-chain evidence

Stack: TypeScript, viem, Ink, Commander.js, Foundry/Anvil

Planned next:

  • veil wallet import Encrypted local keystore support (password-protected)

  • veil send Full flow: decode → risk check → confirm [y/N] → sign → broadcast → wait for receipt

  • Security model write-up Key handling, storage guarantees, and threat model

I'd especially love feedback on the simulation flow and risk engine architecture — those are the parts I'm iterating on most right now.

Repo: github link

reddit.com
u/Economy_Hamster_8645 — 12 days ago