Catalog npm
Back to packageRELEASE DETAILS

1.0.0

npm

2fa-wasm

Biblioteca de autenticación de dos factores (2FA / HOTP / TOTP / Base32 / HMAC) de alto rendimiento en AssemblyScript / WebAssembly con TypeScript wrapper.

2faassemblyscriptbase32google-authenticatorhmachotpotpsha1sha256sha512totpwasmwebassemblyauthenticatorconstant-timeotpauth
All keywords (24)
rfc2104rfc4226rfc4648rfc6238two-factortypescriptzero-alloczero-allocation
Published26 Jul 2026
Direct dependencies0
Transitive dependenciesNot calculated

README

Current package documentation

🔐 2FA WASM

Biblioteca de autenticación de dos factores (2FA) ultra-rápida y de alto rendimiento compilada en WebAssembly (WASM) utilizando AssemblyScript y empaquetada con un wrapper TypeScript Zero-Allocation.

Soporta HOTP (RFC 4226), TOTP (RFC 6238) y Base32 (RFC 4648) sobre HMAC-SHA1 / SHA256 / SHA512 —con validación de tokens en tiempo constante (a prueba de timing attacks) y compatibilidad total con otpauth:// (Google Authenticator, Authy, etc.)— con rendimiento extremo (~478 K TOTP/s rotando los 3 algoritmos) y 0 % de presión sobre el Garbage Collector (GC).


🚀 Características Principales

  • ⚡ Máximo Rendimiento: Núcleo HMAC desplegado en WebAssembly con ~478 000 TOTP/s (rotando SHA-1/256/512) y memoria completamente plana bajo carga.
  • 🧹 Zero-Alloc (Cero Alocaciones GC): Alocador arena estático (memory.data + save/restore) y contextos hash como struct sobre puntero (changetype, sin new en el heap) — WASM Δ 0 B verificado bajo 500 000 operaciones.
  • 🌐 Multiplataforma: Funciona sin modificaciones en Node.js, Bun, Deno y Navegadores Web (Vite, Webpack, etc.).
  • 🛡️ Seguridad Crypto:
    • HMAC-SHA1 / SHA256 / SHA512 (RFC 2104) como primitiva de HOTP/TOTP.
    • Validación constant-time de tokens: comparación por XOR acumulativo sin early-exit, inmune a ataques de timing.
    • Correctitud validada contra vectores oficiales (RFC 4226 Ap. D, RFC 6238 Ap. B, RFC 4648) y node:crypto (36/36 tests).
  • 🔑 HOTP / TOTP: generadores y validadores con ventana de tolerancia, 4–8 dígitos, y los 3 algoritmos (SHA-1 por compatibilidad, SHA-256/512 para mayor seguridad).
  • 📱 Compatibilidad otpauth://: toString() genera URIs escaneables y URI.parse() las reconstruye — integración directa con Google Authenticator, Authy, 1Password, etc.
  • 🔐 Secrets seguros: generación aleatoria con crypto.getRandomValues y conversiones Base32/hex.
  • 📦 Binario Compacto: ~14 KB de WebAssembly optimizado.

📦 Instalación

npm install 2fa-wasm

O con Bun / Yarn / pnpm:

bun add 2fa-wasm

💻 Guía de Uso

1. Inicializar la biblioteca

import { TwoFaWasm } from "2fa-wasm"

// Carga automática desde la URL por defecto (navegador / bundler)
await TwoFaWasm.load()

// O cargando desde un buffer binario explícito (útil para Node.js / Bun):
// import { readFileSync } from "node:fs"
// const wasmBuffer = readFileSync("node_modules/2fa-wasm/dist/2fa.wasm")
// await TwoFaWasm.fromBuffer(wasmBuffer)

La carga se realiza una sola vez. Después puedes usar TOTP / HOTP / Secret / Base32 / URI directamente (usan el singleton global).

2. TOTP (Time-based OTP — RFC 6238)

El caso de uso más común (Google Authenticator y compatibles).

import { TwoFaWasm, TOTP, Secret } from "2fa-wasm"

await TwoFaWasm.load()

// 🔐 Genera un secret nuevo (20 bytes, típico para SHA-1)
const secret = new Secret()
console.log(secret.base32) // → "JBSWY3DPEHPK3PXP…" (para mostrar al usuario / QR)

// 🔑 Genera el código TOTP actual (6 dígitos)
const code = TOTP.generate({ secret })
console.log(code) // → "123456"

// ✅ Valida un código ingresado por el usuario (ventana ±1 por defecto)
const delta = TOTP.validate({ token: code, secret })
console.log(delta) // → 0 (período exacto) | ±1 (ventana) | null (inválido)

// ⏱️ Segundos restantes del período actual
const totp = new TOTP({ secret, period: 30 })
console.log(totp.remaining()) // → 18

🛡️ Para mayor seguridad usa SHA-256/512 y un secret de 32/64 bytes: new TOTP({ secret: new Secret({ size: 32 }), algorithm: "SHA256" }).

3. HOTP (Counter-based OTP — RFC 4226)

import { TwoFaWasm, HOTP, Secret } from "2fa-wasm"

await TwoFaWasm.load()

const secret = Secret.fromBase32("JBSWY3DPEHPK3PXP")

// 🔑 Genera el código HOTP para un counter (vector RFC 4226)
const code = HOTP.generate({ secret, counter: 0 })
console.log(code) // → "755224"

// ✅ Valida con ventana de tolerancia (±window)
const delta = HOTP.validate({ token: "287082", secret, counter: 0, window: 1 })
console.log(delta) // → 1 (el token corresponde al counter 1, dentro de la ventana)

// 🔄 API con estado: el counter se auto-incrementa en cada generate()
const hotp = new HOTP({ secret, counter: 0 })
hotp.generate() // counter 0 → luego incrementa a 1
hotp.generate() // counter 1 → luego incrementa a 2

4. Secret (gestión de la clave compartida)

import { TwoFaWasm, Secret } from "2fa-wasm"

await TwoFaWasm.load()

// 🎲 Aleatorio (20 bytes por defecto; 32/64 para SHA-256/512)
const s1 = new Secret()
const s2 = new Secret({ size: 32 })

// 📥 Desde un Base32 existente (pegado por el usuario)
const s3 = Secret.fromBase32("JBSWY3DPEHPK3PXP")

console.log(s3.base32) // → "JBSWY3DPEHPK3PXP"
console.log(s3.hex) // → "48656c6c6f21deadbeef"
console.log(s3.bytes) // → Uint8Array (bytes crudos)

5. Base32 (RFC 4648)

import { TwoFaWasm, Base32 } from "2fa-wasm"

await TwoFaWasm.load()

const encoded = Base32.encode(new TextEncoder().encode("foobar"))
console.log(encoded) // → "MZXW6YTBOI"

const decoded = Base32.decode("MZXW6YTBOI") // → Uint8Array (bytes de "foobar")

// 🧹 Decode tolerante: acepta lowercase, espacios y padding (típico de secrets pegados a mano)
Base32.decode("mzxw 6ytb oi======") // → mismos bytes

6. URI otpauth:// (compatible con Google Authenticator)

Genera y parsea URIs estándar para códigos QR y migración entre apps.

import { TwoFaWasm, TOTP, URI } from "2fa-wasm"

await TwoFaWasm.load()

const totp = new TOTP({
  issuer: "MiApp",
  label: "usuario@ejemplo.com",
  secret: "JBSWY3DPEHPK3PXP",
  algorithm: "SHA1",
  digits: 6,
  period: 30
})

// 📱 Genera la URI otpauth:// (para el código QR)
const uri = totp.toString()
// → "otpauth://totp/MiApp:usuario%40ejemplo.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&period=30&issuer=MiApp"

// 📥 Reconstruye desde una URI (ej. escaneada o importada)
const parsed = URI.parse(uri)
console.log(parsed.issuer) // → "MiApp"
console.log(parsed.generate()) // → código TOTP actual

URI.parse() devuelve una instancia HOTP o TOTP según el tipo de URI, lista para generate()/validate().

7. API de bajo nivel (TwoFaWasm)

Acceso directo a las primitivas del WASM (uso avanzado).

import { TwoFaWasm } from "2fa-wasm"

const wasm = await TwoFaWasm.load()

// 🔏 HMAC directo (SHA1 / SHA256 / SHA512)
const mac = wasm.hmac("SHA256", clave, mensaje) // → Uint8Array

// ⏱️ Counter y segundos restantes de TOTP
const counter = wasm.totpCounter(30) // counter del período actual
const remaining = wasm.totpRemaining(30) // segundos restantes

// 🔑 Generación/validación raw (bytes, sin formatear)
const code = wasm.hotpGenerate(secretBytes, 0, 6, "SHA1") // → "755224"
const delta = wasm.totpValidate("123456", secretBytes, Date.now(), 30, 6, 1, "SHA1")

8. Utilidades

import { bytesToHex, hexToBytes, toUint8Array, getRandomBytes } from "2fa-wasm"

const hex = bytesToHex(new Uint8Array([0xde, 0xad, 0xbe, 0xef])) // "deadbeef"
const bytes = hexToBytes("deadbeef") // Uint8Array(4)
const utf8 = toUint8Array("texto") // string → Uint8Array (UTF-8)
const random = getRandomBytes(32) // 32 bytes aleatorios (crypto-safe)

📊 Benchmarks de Rendimiento

Pruebas ejecutadas en Bun (JavaScriptCore) sobre un procesador x86-64 moderno, en single-thread:

OperaciónRendimientoMemoria
TOTP generate (3 algoritmos rotados)~478 K ops/s—
Estrés 500 000 opsestable (~478 K ops/s)WASM Δ 0 B
Heap JS tras 500 000 ops—Δ ~0.02 MB

Rondas de estrés (zero-alloc verificado):

IteracionesOps/segHeap ΔWASM Δ
10 000328 1850.00 MB0 B
50 000477 6660.00 MB0 B
100 000486 2510.00 MB0 B
500 000478 3870.02 MB0 B

El throughput se estabiliza (~478 K ops/s) en lugar de degradarse, y la memoria lineal del WASM nunca crece (Δ 0 B) — la garantía zero-alloc se cumple bajo carga real, no solo en el caso feliz.

Validación de correctitud (36/36 tests):

EstándarCobertura
HOTP — RFC 4226, Ap. D10 contadores (SHA-1, 6 dígitos) + ventana/delta
TOTP — RFC 6238, Ap. B6 timestamps × SHA-1/256/512 (8 dígitos)
Base32 — RFC 4648vectores + tolerancia (padding/lowercase/espacios)
HMAC — vs node:cryptoSHA-1/256/512 + clave larga (> bloque)

🏗️ Arquitectura Zero-Allocation

  • Alocador arena estático: 32 KB reservados en el data segment del WASM en tiempo de compilación (memory.data), con save()/restore() por operación — ninguna reserva toca el heap del runtime.
  • Contextos como struct sobre puntero: los contextos hash (SHA-1/256/512) se superponen sobre el scratchpad vía changetype (sin new), eliminando por completo las alocaciones en el heap.
  • Validación constant-time: hotp_validate_raw compara el token generado con el recibido mediante XOR + OR acumulativo de longitud fija (sin early-exit), evitando fugas por timing.
  • Única asignación: el string del código OTP que se entrega al usuario (inevitable); todo lo demás vive en el scratchpad.
  • Resultado verificado: WASM Δ 0 B y heap estable bajo 500 000 operaciones.

🛠️ Comandos de Desarrollo

# Compilar binario WASM (AssemblyScript) + bundle TypeScript (esbuild minificado)
bun run build

# Compilar solo el binario WASM
bun run asbuild          # release → dist/2fa.wasm
bun run asbuild:debug    # debug → build/debug.wasm + .wat + sourcemap

# Verificación de tipos
bun run typecheck

# Tests (suite de correctitud + estrés zero-alloc)
bun test

📁 Estructura del Proyecto

2fa-wasm/
├── assembly/            # Núcleo en AssemblyScript (→ WebAssembly)
│   ├── index.ts         # Exportaciones WASM (hmac, base32, hotp, totp)
│   ├── memory.ts        # Alocador arena estático (Memory: alloc/save/restore)
│   ├── sha1.ts          # SHA-1 (struct sobre puntero, compress desplegado)
│   ├── sha2/
│   │   ├── sha256.ts    # SHA-256 (sliding-window)
│   │   ├── sha512.ts    # SHA-512 (sliding-window)
│   │   ├── constants.ts # Constantes K e IV
│   │   └── common.ts    # Helpers (bswap, Ch, Maj, Sigma, sigma)
│   ├── hmac.ts          # Dispatch HMAC interno (SHA1/256/512)
│   ├── hotp.ts          # HOTP (RFC 4226, validación constant-time)
│   ├── totp.ts          # TOTP (RFC 6238)
│   └── base32.ts        # Base32 (RFC 4648, decode tolerante)
├── src/                 # Wrapper en TypeScript
│   ├── index.ts         # Punto de entrada (re-exports)
│   ├── twofa-wasm.ts    # Cargador (load/fromUrl/fromBuffer) + API bajo nivel
│   ├── allocator.ts     # WasmAllocator (caché de heap, zero-alloc)
│   ├── base32.ts        # Base32
│   ├── secret.ts        # Secret (bytes/base32/hex)
│   ├── hotp.ts          # HOTP + interfaces
│   ├── totp.ts          # TOTP + interfaces
│   ├── uri.ts           # Parser otpauth://
│   └── types.ts         # Tipos (HashAlgorithm, configs) + utilidades
├── test/
│   ├── index.test.ts    # Suite de correctitud (RFC 4226/6238/4648, node:crypto)
│   └── stress.test.ts   # Estrés zero-alloc (WASM Δ 0 B)
├── dist/                # Build (generado)
├── asconfig.json        # Configuración de AssemblyScript
├── package.json
├── tsconfig.json
├── LICENSE              # Apache-2.0
└── README.md

📜 Licencia

Apache License 2.0 © Edison Manrique

Exención de responsabilidad: este software se proporciona "tal cual" (AS IS), sin garantía de ningún tipo. Aunque HOTP, TOTP, HMAC y Base32 son estándares (RFC 4226 / RFC 6238 / RFC 2104 / RFC 4648), esta implementación no ha sido auditada formalmente y no debe emplearse en aplicaciones de seguridad crítica sin verificación independiente.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 0

Native requirements
0 direct targetsNot calculated transitive count
No declared dependencies in this collected response

Declarations describe requirements; they are not a resolved dependency graph.

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "563ebf2e4a1761b72bb622b4b45724ad0ecedf94",
  "tarball": "https://registry.npmjs.org/2fa-wasm/-/2fa-wasm-1.0.0.tgz",
  "fileCount": 6,
  "integrity": "sha512-sKzjRtA7NdRcwCs58efmGjnoCndGfiGrgAf0GDumPgnKrJ3l4QY+/oBwFUZ1gAPZzFheo4dD6DQqtorHJbhaOw==",
  "signatures": [
    {
      "sig": "MEUCIA6DKjced/vTlC9Ul3/WoF9+EMia2QF4tYMBrZEPHlzuAiEA8dRAwSYLrzCwwNCqHrXP/mN6s0gvVxJ6GX3BiRig46c=",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "unpackedSize": 44657
}

Repository

PENDING
edison-manrique/2fa-wasm

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:12 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:afc55e73bef2706e905e2bf65530a577e5cfaa4b2b560a0c78bf8a88d1aed9dc

Other collected versions

1.1.129 Jul1.1.029 JulView all collected versions →