ssvault / lite

Argon2id, HKDF y Workers.
Decisiones criptográficas
sin humo.

Cómo Lite deriva, aísla y calibra cada credencial. Contexto suficiente para auditar sin convertir la pantalla principal en documentación.

ARQUITECTURA

Pipeline de derivación Lite v1

Master password + canonical ID → Argon2id → root key → HKDF por contexto → password, passphrase y visual fingerprint. El resultado final nunca se persiste.

masterPassword + canonicalId Argon2id(salt=SHA256(prefix|canonicalId)) rootKey

rootKey HKDF-SHA-256(info="password"|"passphrase"|"visual") output

La sal de Argon2id es determinista (derivada del canonical ID) porque Lite no persiste secretos per-credential. HKDF separa contextos para que password, passphrase y visual fingerprint nunca reutilicen los mismos bytes.

01 · Identidad canónica

Servicio, cuenta opcional, namespace, perfil, calibración Argon2, modo y versión forman el request estable sobre el que se deriva todo lo demás. Cada token se normaliza con NFKC, se pasa a lowercase y se limpian separadores (smart quotes, barras, dos puntos) para producir un ID determinista:

lite|svc=github|acct=alice|ns=personal|profile=web|cal=balanced|mode=password|v=1

Tokens vacíos usan fallbacks estables: servicio → service, cuenta → account, namespace → default. Esto garantiza que el ID canónico siempre sea válido aunque el usuario deje campos opcionales vacíos.

02 · Aislamiento y calibración

La derivación prioriza Web Worker para aislar la master password del hilo principal. Si el Worker no está disponible o falla, cae con honestidad al hilo principal reportando el motivo del fallback. No hay fallo silencioso. Lite parte de balanced como nivel por defecto y ofrece un botón para autoajustar según hardware, pero el nivel final lo fija el usuario en el formulario y forma parte del canonical ID.

Niveles de calibración Argon2id

constrained 32 MiB · t=3 · p=1
balanced 64 MiB · t=3 · p=1
strong 96 MiB · t=3 · p=1
max 128 MiB · t=4 · p=1

Balanced es el valor inicial por defecto. Si usas el botón de autoajuste, Lite recomienda un nivel según el hardware del dispositivo: ≤2 cores o ≤2 GiB → constrained; ≥12 cores + ≥16 GiB → max. El usuario puede cambiar el nivel en cualquier momento. OJO: cambiar la calibración cambia la contraseña o passphrase derivada. Para obtener el mismo resultado en distintos dispositivos, debe usarse el mismo nivel de calibración.

03 · Persistencia mínima

Lite persiste lo mínimo necesario para una experiencia fluida sin comprometer secretos.

localStorage Preferencias mínimas: perfil activo, modo, opciones de password/passphrase. Se lee al montar el componente y se actualiza con debounce.
IndexedDB Perfiles guardados con su identificador canónico completo. Soporta CRUD (crear, leer, actualizar, eliminar) y reemplazo completo vía import.
Export/Import Formato ssvault-lite-config v1. Envelope contract-first. Sanitización estricta al importar: cada perfil se valida individualmente y los inválidos se descartan en silencio.

Toda operación de almacenamiento pasa por lite-storage-contract.ts que valida estructura, tipos y rangos antes de persistir. Datos fuera del contrato se rechazan o descartan.

04 · CSP y hardening

Astro SSR aplica headers de seguridad vía middleware en cada respuesta. Las directivas CSP del servidor complementan los hashes per-page que Astro genera automáticamente para scripts y estilos.

script-src: no permite unsafe-inline. Incluye wasm-unsafe-eval para hash-wasm.

style-src: permite unsafe-inline (atributos inline del visual fingerprint).

worker-src: self blob: para bundling de workers.

frame-ancestors: none (no se puede embeber en iframes).