Skip to content

HenryXCC/lockbox

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔐 LockBox

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.

Build Runtime deps Crypto i18n Tests License


EN — English

Quick start

  1. Download lockbox.html from this repository.
  2. Open it in Chrome, Firefox, or Edge.
  3. Create your master password.
  4. (Optional) Go to Import backup → select demo-backup.lockbox → password: Demo1234!

No npm install, no build step, no account. Just the file.

Features

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:// and https:// 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.length approaches.
  • 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 ⏰ OLD badge 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 .lockbox file 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/https only).
  • 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 shortcutsAlt+N new entry · Alt+L lock · Ctrl+F search · Esc close 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-visible for keyboard-first users without affecting mouse users.
  • Skip-link for screen readers.
  • Support for prefers-reduced-motion.
  • Enter/Space activation on interactive elements.

Security architecture

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.


Test suite

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.


Screenshots

Login screen

Main vault view

Password generator

Settings modal

Test runner


Project structure

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

Tech stack

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

Important notes

  • 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.com for the opt-in breach check and blocks all other outbound requests.

Security notice

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.


ES — Español

Inicio rápido

  1. Descarga lockbox.html desde este repositorio.
  2. Ábrelo en Chrome, Firefox o Edge.
  3. Crea tu contraseña maestra.
  4. (Opcional) Ve a Importar backup → selecciona demo-backup.lockbox → contraseña: Demo1234!

Sin npm install, sin build, sin cuenta. Solo el archivo.

Características

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:// y https:// 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 ⏰ ANTIGUA y 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 .lockbox es 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 tecladoAlt+N nueva entrada · Alt+L bloquear · Ctrl+F buscar · Esc cerrar 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-visible para 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.

Arquitectura de seguridad

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.


Suite de tests

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.


Capturas de pantalla

Pantalla de login

Vista principal del vault

Generador de contraseñas

Modal de configuración

Test runner


Estructura del proyecto

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

Stack técnico

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

Notas importantes

  • 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.com para la verificación opt-in de brechas y bloquea cualquier otra petición de red.

Aviso de seguridad

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.


License / Licencia

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.

About

Password manager in a single HTML file. AES-256-GCM, TOTP/2FA, HIBP breach check. Zero dependencies.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages