Una contraseña de un solo uso basada en tiempo (TOTP) es el código de seis dígitos que una aplicación de autenticación muestra para una cuenta, actualizándose cada treinta segundos. La define la RFC 6238, que se apoya en la contraseña de un solo uso basada en HMAC de la RFC 4226. El diseño es deliberadamente simple: un secreto compartido más la hora actual producen un código que tanto tu dispositivo como el servidor pueden calcular de forma independiente, sin ninguna comunicación de red y sin nada que interceptar.
El Secreto Compartido
El alta empieza cuando un servicio genera un secreto aleatorio — normalmente de dieciséis a veinte bytes — y te lo muestra, habitualmente codificado como texto base32 y empaquetado dentro de un código QR. Tu autenticador guarda ese secreto; el servidor guarda el mismo secreto asociado a tu cuenta. A partir de entonces ambos lados tienen material de clave idéntico y nunca necesitan volver a intercambiarlo. Se usa base32 (RFC 4648) porque su alfabeto evita caracteres ambiguos y sobrevive a escribirse a mano.
El Paso de Tiempo
En lugar de un contador que ambos lados deben mantener sincronizado, TOTP deriva el contador del reloj. Toma el número de segundos desde la época Unix y lo divide entre el periodo — treinta segundos por defecto — descartando el resto. Todos con un reloj razonablemente correcto calculan el mismo contador para la misma ventana de treinta segundos, por lo que el código es el mismo en tu teléfono y en el servidor sin que ninguno hable con el otro.
HMAC y Truncamiento Dinámico
Ese contador de ocho bytes se firma con HMAC bajo el secreto compartido, usando SHA-1 por defecto (algunos servicios eligen SHA-256 o SHA-512). El resultado es un valor de veinte bytes, demasiado largo para teclear. La RFC 4226 define un "truncamiento dinámico" para reducirlo: toma los cuatro bits bajos del último byte como desplazamiento, lee los cuatro bytes que empiezan en ese desplazamiento, enmascara el bit superior para mantenerlo positivo y reduce el número resultante módulo diez elevado al número de dígitos. Lo que queda es tu código de seis, siete u ocho dígitos, rellenado con ceros por la izquierda.
Por Qué Ambos Lados Deben Coincidir
Como el código queda completamente determinado por el secreto, el algoritmo, el número de dígitos y el periodo, ambos lados deben coincidir en los cuatro. Un autenticador que asume SHA-1 y seis dígitos producirá en silencio códigos erróneos para un servicio que espera SHA-256 u ocho dígitos — las matemáticas funcionan, solo que dan un número distinto. Por eso la URI otpauth:// lleva el algoritmo, los dígitos y el periodo junto al secreto.
Deriva del Reloj y Ventanas de Validación
Como el contador proviene de la hora del reloj, un dispositivo cuyo reloj esté más de un paso desincronizado calcula el contador de la ventana equivocada y produce un código que el servidor rechaza. Para absorber pequeñas derivas, los servidores suelen aceptar los códigos de las ventanas adyacentes — un paso antes y después — en lugar de solo el exacto. Un desfase grande sigue fallando, y es la razón más común por la que un código "no funciona" a pesar de que el secreto es correcto.
Qué Guarda el Servidor
El servidor guarda solo el secreto compartido y los parámetros, y recalcula el código esperado en cada inicio de sesión para compararlo con lo que tecleaste. No registra nada predictivo e, idealmente, recuerda el último paso aceptado para que un código no pueda reutilizarse dentro de su propia ventana. No hay base de datos de códigos ni transformación reversible: el mismo HMAC unidireccional corre en ambos extremos, y eso es lo que hace a TOTP capaz de funcionar sin conexión y difícil de phishear solo por interceptación.