EN — Offline, local, fully functional password manager contained in a single HTML file. No servers, no runtime dependencies, no installation.
ES — Gestor de contraseñas offline, local y completamente funcional contenido en un único archivo HTML. Sin servidores, sin dependencias >de runtime, sin instalación.
- Download
lockbox.htmlfrom this repository. - Open it in Chrome, Firefox, or Edge.
- Create your master password.
- (Optional) Go to Import backup → select
demo-backup.lockbox→ password:Demo1234!
No npm install, no build step, no account. Just the file.
Security
- AES-256-GCM via native Web Crypto API — no third-party libraries.
- PBKDF2 with 310,000 iterations (OWASP 2023 recommendation for SHA-256).
- Random 96-bit IV per encryption — IV reuse in AES-GCM is a critical vulnerability; it never happens here.
- Implicit GCM authentication tag — any tampered or incorrectly decrypted data is automatically rejected.
- Master key never touches
localStorage— only the encrypted blob is persisted; the key lives in memory and is cleared on lock. - Clipboard cleared after 30 seconds — system clipboard cleanup is subject to browser permissions.
- Auto-lock on inactivity — configurable: 1 / 5 / 15 / 30 minutes.
- Listeners managed with
AbortController— correctly cleaned up on each lock/unlock cycle, no accumulation. - Passwords are not rendered in cards or HTML attributes — retrieved from memory only when needed.
- URL protocol validation — only
http://andhttps://URLs render as clickable links;javascript:and other schemes are shown as plain text. - Unbiased password generation — rejection sampling eliminates the modulo bias present in
x % charset.lengthapproaches. - HIBP breach check with k-anonymity — opt-in feature (Settings). Sends only the first 5 hex characters of the SHA-1 hash to
api.pwnedpasswords.com; the server never sees the full password or hash.
Vault management
- 6 categories — Web, Email, Bank, Social, Work, Other — with color coding.
- Favorites — star any entry to pin it to the ⭐ Favorites filter in the sidebar.
- Health dashboard — shows weak 🔴, reused 🟠, old ⏰, regular 🟡 and strong 🟢 passwords; each bucket is clickable to filter. After a HIBP scan, a breached ☠️ bucket appears.
- Password age warning — entries whose password has not changed in over 90 days receive an
⏰ OLDbadge and appear in the health dashboard's "old" bucket. - Reused password detection — automatic badge when two entries share a password.
- Weak password detection — automatic badge based on strength score.
- HIBP breach check — opt-in button in the health panel; checks all vault passwords against the haveibeenpwned.com database with k-anonymity. Results are transient (not persisted) and cleared on lock.
- Password history — last 10 previous passwords per entry, with change date.
- Sorting — by date, name or strength; preference persisted between sessions.
- Real-time search — across name, username and URL simultaneously.
- Password generator — two modes: Random (length 8–64, configurable character types) and Passphrase (3–8 words from a curated 200-word list, custom separator, capitalize option). Both use rejection sampling to eliminate modulo bias.
- TOTP / 2FA storage — store a Base32 secret or
otpauth://URI per entry. The live 6-digit code is shown directly on the card with a color-coded 30-second countdown bar (green → yellow → red). Implemented from scratch using WebCrypto HMAC-SHA1 + RFC 4226 truncation — no libraries. - CSV import — accepts Chrome and Bitwarden export formats; auto-detects the format from the header row. Includes a built-in RFC 4180 parser that handles quoted fields, escaped quotes, and embedded newlines.
- Encrypted export / import — the
.lockboxfile is unreadable without the master password. - CSV export — plaintext export for migrating to another manager; clearly marked as unencrypted with a warning.
- URLs as links — open directly from the card (validated to
http/httpsonly). - Drag & drop to import backups.
UX
- Live language switching — toggle between Spanish and English with one click, without closing the app or losing any data.
- Password hint — optional when creating the vault; visible on the login screen on demand.
- Keyboard shortcuts —
Alt+Nnew entry ·Alt+Llock ·Ctrl+Fsearch ·Escclose modal. - Fully responsive — sliding sidebar on mobile, single-column layout.
- Custom confirmation modal — avoids the browser's blocking
window.confirm(). - Web Crypto API validation — graceful degradation with a clear message if the browser doesn't support it.
Accessibility
- Full keyboard navigation.
focus-visiblefor keyboard-first users without affecting mouse users.- Skip-link for screen readers.
- Support for
prefers-reduced-motion. - Enter/Space activation on interactive elements.
Master password
│
▼
PBKDF2-SHA256 · 310,000 iterations · random 32-byte salt
│
▼
AES-256-GCM key ────────────────────────── memory only
│ cleared on lock()
▼
Encrypt vault JSON
(random 12-byte IV per save)
│
▼
[salt 32B][iv 12B][ciphertext + GCM auth tag] → base64 → localStorage
What does an attacker get with access to localStorage?
A base64 blob computationally infeasible to decrypt without the master password. The AES-GCM authentication tag rejects any tampered or incorrectly decrypted data.
What is stored in plain text?
- The password hint (intentional — it's a memory aid, not a secret).
- UI preferences (timeout, sort order, language).
Threat model
The encryption protects against direct localStorage access (disk dump, another process, extension without XSS privileges). It does not protect against malicious extensions with JS context access, active XSS, or memory inspection while the vault is unlocked — this is inherent to any web-based password manager and is mitigated by the strict CSP and auto-lock.
The project includes a standalone test suite (lockbox.tests.html) with no external dependencies. It covers encryption and decryption, IV generation, strength scoring, duplicate detection, password history, and failure cases.
To run it, open lockbox.tests.html in the browser — tests run automatically. The suite is available in both Spanish and English via the same language selector as the main application.
lockbox.html ← full application (~4100 lines, HTML + CSS + JS)
lockbox.tests.html ← standalone browser test suite (71 tests)
assets/
├── screenshot_login_es.png
├── screenshot_login_en.png
├── screenshot_vault_es.png
├── screenshot_vault_en.png
├── screenshot_generator_es.png
├── screenshot_generator_en.png
├── screenshot_settings_es.png
├── screenshot_settings_en.png
├── screenshot_tests_es.png
└── screenshot_tests_en.png
README.md
LICENSE
.gitignore
| Layer | Technology |
|---|---|
| Cryptography | Web Crypto API (AES-GCM + PBKDF2 + HMAC-SHA1) |
| TOTP | RFC 6238 + RFC 4226 — pure WebCrypto, no libraries |
| Storage | localStorage (encrypted blobs only) |
| UI | Vanilla JS + CSS custom properties |
| Typography | Sora + JetBrains Mono (Google Fonts) |
| i18n | Custom system based on data-i18n + LANGS object |
| Build | None |
| Framework | None |
| Runtime | Any modern browser |
- There is no master password recovery. Encryption is local and has no backdoor. If you lose it, your data is unrecoverable. Export backups regularly.
- Data is local to the device. Nothing leaves the browser. Use Export / Import to move data between devices.
- The HIBP breach check is opt-in and requires network. It uses k-anonymity — only a 5-character hash prefix is sent; your passwords never leave the device. The feature is off by default; results are cleared on lock.
- The hint is not encrypted. By design — it's a reminder, not a second factor. Don't put sensitive information there.
- External fonts on first load. Google Fonts loads the first time the file is opened; after that it works completely offline. The CSP allows
api.pwnedpasswords.comfor the opt-in breach check and blocks all other outbound requests.
This project is for personal/portfolio use and has not undergone a professional security audit. The cryptographic implementation uses correct primitives (AES-256-GCM, PBKDF2-SHA256, random IVs), but should not be considered equivalent to audited software for high-risk or enterprise environments.
- Descarga
lockbox.htmldesde este repositorio. - Ábrelo en Chrome, Firefox o Edge.
- Crea tu contraseña maestra.
- (Opcional) Ve a Importar backup → selecciona
demo-backup.lockbox→ contraseña:Demo1234!
Sin npm install, sin build, sin cuenta. Solo el archivo.
Seguridad
- AES-256-GCM vía Web Crypto API nativa — sin librerías de terceros.
- PBKDF2 con 310.000 iteraciones (recomendación OWASP 2023 para SHA-256).
- IV aleatorio de 96 bits por cada cifrado — reutilizar un IV en AES-GCM es una vulnerabilidad crítica; aquí nunca ocurre.
- Authentication tag implícito de GCM — cualquier dato manipulado o descifrado incorrectamente es rechazado automáticamente.
- La clave maestra nunca toca
localStorage— solo el blob cifrado se persiste; la clave vive en memoria y se limpia al bloquear. - Portapapeles se limpia a los 30 segundos — la limpieza del clipboard del sistema queda sujeta a permisos del navegador.
- Auto-bloqueo por inactividad — configurable: 1 / 5 / 15 / 30 minutos.
- Listeners gestionados con
AbortController— se limpian correctamente en cada ciclo de lock/unlock, sin acumulación. - Las contraseñas no se renderizan en tarjetas ni atributos HTML — se obtienen desde memoria únicamente cuando son necesarias.
- Validación de protocolo en URLs — solo
http://yhttps://se renderizan como enlaces clickeables;javascript:y otros esquemas se muestran como texto plano. - Generación sin sesgo estadístico — se usa rejection sampling para eliminar el sesgo de módulo presente en
x % charset.length. - Verificación de brechas HIBP con k-anonymity — feature opt-in (Configuración). Solo se envían los primeros 5 caracteres hexadecimales del hash SHA-1 a
api.pwnedpasswords.com; el servidor nunca ve la contraseña ni el hash completo.
Gestión del vault
- 6 categorías — Web, Email, Banco, Social, Trabajo, Otros — con código de color.
- Favoritos — marca cualquier entrada con ⭐ para fijarla al filtro de Favoritos del sidebar.
- Dashboard de salud — muestra débiles 🔴, reutilizadas 🟠, antiguas ⏰, regulares 🟡 y fuertes 🟢; cada bucket es clickeable para filtrar. Tras un scan de HIBP aparece el bucket comprometidas ☠️.
- Aviso de contraseña antigua — las entradas cuya contraseña no ha cambiado en más de 90 días reciben el badge
⏰ ANTIGUAy aparecen en el bucket "antiguas" del dashboard. - Detección de contraseñas reutilizadas — badge automático cuando dos entradas comparten contraseña.
- Detección de contraseñas débiles — badge automático basado en score de fortaleza.
- Verificación de brechas HIBP — botón opt-in en el panel de salud; comprueba todas las contraseñas del vault contra haveibeenpwned.com con k-anonymity. Los resultados son transientes (no se persisten) y se limpian al bloquear.
- Historial de contraseñas — últimas 10 contraseñas anteriores por entrada, con fecha de cambio.
- Ordenamiento — por fecha, nombre o fortaleza; preferencia persistida entre sesiones.
- Búsqueda en tiempo real — sobre nombre, usuario y URL simultáneamente.
- Generador de contraseñas — dos modos: Aleatoria (longitud 8–64, tipos de carácter configurables) y Frase (3–8 palabras de una lista curada de 200, separador personalizado, capitalización). Ambos usan rejection sampling para eliminar el sesgo de módulo.
- Almacenamiento TOTP / 2FA — guarda un secreto Base32 o URI
otpauth://por entrada. El código de 6 dígitos en vivo se muestra directamente en la tarjeta con una barra de cuenta atrás de 30 segundos con código de color (verde → amarillo → rojo). Implementado desde cero con WebCrypto HMAC-SHA1 + truncación RFC 4226 — sin librerías. - Import CSV — acepta formatos de exportación de Chrome y Bitwarden; detecta el formato automáticamente por la fila de headers. Incluye un parser RFC 4180 propio que maneja campos entre comillas, comillas escapadas y saltos de línea incrustados.
- Export / Import cifrado — el archivo
.lockboxes ilegible sin la contraseña maestra. - Export CSV — exportación en texto plano para migrar a otro gestor; claramente marcado como no cifrado con aviso.
- URLs como enlaces — se abren directamente desde la tarjeta (validadas a
http/httpsúnicamente). - Drag & drop para importar backups.
UX
- Cambio de idioma en vivo — alterna entre español e inglés con un clic sin cerrar la app ni perder ningún dato.
- Pista de contraseña — opcional al crear la bóveda; visible en el login a pedido.
- Atajos de teclado —
Alt+Nnueva entrada ·Alt+Lbloquear ·Ctrl+Fbuscar ·Esccerrar modal. - Totalmente responsive — sidebar deslizable en mobile, layout de una columna.
- Modal de confirmación personalizado — evita el
window.confirm()bloqueante del navegador. - Validación de Web Crypto API — degradación elegante con mensaje claro si el navegador no la soporta.
Accesibilidad
- Navegación completa por teclado.
focus-visiblepara usuarios keyboard-first sin afectar usuarios de mouse.- Skip-link para lectores de pantalla.
- Soporte para
prefers-reduced-motion. - Activación con Enter/Espacio en elementos interactivos.
Contraseña maestra
│
▼
PBKDF2-SHA256 · 310.000 iteraciones · salt aleatorio de 32 bytes
│
▼
Clave AES-256-GCM ──────────────────────── solo en memoria
│ se limpia en lock()
▼
Cifrar vault JSON
(IV aleatorio de 12 bytes por cada guardado)
│
▼
[salt 32B][iv 12B][ciphertext + auth tag GCM] → base64 → localStorage
¿Qué obtiene un atacante con acceso al localStorage?
Un blob base64 computacionalmente infeasible de descifrar sin la contraseña maestra. El authentication tag de AES-GCM rechaza cualquier dato manipulado.
¿Qué se guarda en texto plano?
- La pista de contraseña (intencional — es un recordatorio, no un secreto).
- Preferencias de UI (timeout, orden, idioma).
Modelo de amenaza
El cifrado protege contra acceso directo al localStorage (volcado de disco, otro proceso, extensión sin privilegios XSS). No protege contra extensiones maliciosas con acceso al contexto JS, XSS activo o inspección de memoria mientras el vault está desbloqueado — esto es inherente a cualquier password manager web-based y se mitiga con la CSP estricta y el auto-bloqueo.
El proyecto incluye una suite de tests standalone (lockbox.tests.html) sin dependencias externas. Cubre cifrado y descifrado, generación de IVs aleatorios, scoring de fortaleza, detección de duplicados, historial de contraseñas y casos de fallo.
Para ejecutarla, abre lockbox.tests.html en el navegador — los tests corren automáticamente. La suite está disponible en español e inglés mediante el mismo selector de idioma del archivo principal.
lockbox.html ← aplicación completa (~4100 líneas, HTML + CSS + JS)
lockbox.tests.html ← suite de tests standalone en navegador (71 tests)
assets/
├── screenshot_login_es.png
├── screenshot_login_en.png
├── screenshot_vault_es.png
├── screenshot_vault_en.png
├── screenshot_generator_es.png
├── screenshot_generator_en.png
├── screenshot_settings_es.png
├── screenshot_settings_en.png
├── screenshot_tests_es.png
└── screenshot_tests_en.png
README.md
LICENSE
.gitignore
| Capa | Tecnología |
|---|---|
| Criptografía | Web Crypto API (AES-GCM + PBKDF2 + HMAC-SHA1) |
| TOTP | RFC 6238 + RFC 4226 — WebCrypto puro, sin librerías |
| Storage | localStorage (solo blobs cifrados) |
| UI | Vanilla JS + CSS custom properties |
| Tipografía | Sora + JetBrains Mono (Google Fonts) |
| i18n | Sistema propio basado en data-i18n + objeto LANGS |
| Build | Ninguno |
| Framework | Ninguno |
| Runtime | Cualquier navegador moderno |
- No hay recuperación de contraseña maestra. El cifrado es local y sin backdoor. Si la pierdes, los datos son irrecuperables. Exporta backups regularmente.
- Los datos son locales al dispositivo. Nada sale del navegador. Para mover datos entre dispositivos usa Export / Import.
- La verificación de brechas HIBP es opt-in y requiere conexión. Usa k-anonymity — solo se envía un prefijo de 5 caracteres del hash; las contraseñas nunca salen del dispositivo. La función está desactivada por defecto; los resultados se limpian al bloquear.
- La pista no está cifrada. Por diseño — es un recordatorio, no un segundo factor. No pongas información sensible ahí.
- Fuentes externas en primera carga. Google Fonts se carga al abrir el archivo por primera vez; tras ese cache, funciona completamente offline. La CSP permite
api.pwnedpasswords.compara la verificación opt-in de brechas y bloquea cualquier otra petición de red.
Este proyecto es de uso personal/portfolio y no ha sido sometido a una auditoría de seguridad profesional. La implementación criptográfica usa primitivas correctas (AES-256-GCM, PBKDF2-SHA256, IVs aleatorios), pero no debe considerarse equivalente a software auditado para entornos de alto riesgo o enterprise.
Distributed under the MIT license. See the LICENSE file for details.
Distribuido bajo la licencia MIT. Consulta el archivo LICENSE para más detalles.
Developed as a portfolio project. All processing is local; no data is sent to the project's own servers. Typography fonts are loaded from Google Fonts on first open.
Desarrollado como proyecto de portafolio. Todo el procesamiento es local; no se envía ningún dato a servidores propios del proyecto. Las fuentes tipográficas se cargan desde Google Fonts en la primera apertura.









