Time-based One-time Password: TOTP explicado
Los usuarios de Internet deben introducir contraseñas de manera habitual, por ejemplo para iniciar sesión en una plataforma de red social, en una tienda o en una banca online. Las contraseñas evitan el acceso de terceros a datos sensibles. Sin embargo, muchos usuarios no prestan la atención necesaria, pues los profesionales son capaces de descifrar contraseñas sencillas en cuestión de segundos. Mientras tanto, otros usuarios guardan contraseñas de buena calidad de manera incorrecta, lo que proporciona a los delincuentes una puerta de entrada. Además, no hay que olvidar los puntos débiles de los servicios en los que se inicia sesión. Si las contraseñas no se almacenan de manera adecuada, se ponen en peligro los datos de miles de usuarios.
Una posibilidad para reducir el riesgo es la autentificación de dos factores o autentificación multifactor. En lugar de utilizar una única contraseña, es necesario introducir como mínimo un elemento más de autentificación. Los usuarios la reciben a través del smartphone o de un token de hardware. Generalmente, los factores adicionales se caracterizan por ser únicos y tener una validez limitada a un breve periodo de tiempo. Es decir, se genera un llamado Time based One time Password. Te explicamos cómo funciona.
¿Para qué se necesita TOTP?
Por muy seguras que sean las contraseñas comunes, siempre presentan un inconveniente: en cuanto alguien más conoce la secuencia de caracteres, la seguridad desaparece. Una posible solución sería cambiar habitualmente la contraseña, pero incluso los usuarios más ejemplares no van a hacerlo cada hora. TOTP representa la solución: se trata de una contraseña válida únicamente durante un breve periodo de tiempo que después caduca. El Grupo de trabajo de ingeniería de internet (IETF) publicó en 2011 el algoritmo Time-based One-time Password en el RFC 6238 para proporcionar una mayor seguridad en Internet.
Estas contraseñas únicas son especialmente populares como parte de una autentificación multifactor. Para ello, en el inicio de sesión en un servicio web los usuarios utilizan en primer lugar su contraseña personal fija y, de manera adicional, se genera una contraseña especial para ese proceso de inicio de sesión durante un periodo limitado. El usuario la recibe, p. ej. a través de una app o de un dispositivo especial (token).
Si la contraseña se utiliza una vez o no se utiliza durante un determinado periodo de tiempo, caduca. Por lo tanto, para los criminales es muy complicado acceder al segundo factor. Incluso aunque conozcan la contraseña, tendrán muy pocas posibilidades de solicitar también el TOTP o no dispondrán del tiempo suficiente para descifrarlo.
¿Cómo funciona el algoritmo Time-based One-time Password?
La base del TOTP es una función hash, es decir, un procedimiento criptográfico. A partir de una contraseña secreta y de una marca de tiempo se forma una secuencia de caracteres codificada. La contraseña es conocida tanto para el usuario como para el servidor. La indicación de tiempo se lleva a cabo en tiempo Unix.
El tiempo Unix es un valor que indica los segundos transcurridos desde el 1 de enero de 1970.
TOTP es en realidad la evolución de HOTP, siglas de «HMAC-based One-time Password». TOTP también está basado en el procedimiento HMAC, la operación hash en segundo plano. Tanto el dispositivo del usuario como el servidor generan un valor hash a partir de la contraseña secreta en combinación con un contador. Dado que ambos valores son idénticos, la autentificación funciona.
La función hash en sí no está definida; en la práctica se recurre p. ej. a SHA-1 (como en el caso de Google Authenticator), que genera un valor hash con una longitud de 160 bits. Para simplificar, este valor se acorta por medio de una función de compresión. Al final se cuenta, por ejemplo, con un número de seis cifras que el usuario puede introducir fácilmente al iniciar sesión en el servicio web.
En el caso de los tokens, la contraseña secreta está anclada en el dispositivo y a menudo el usuario no sabe cuál es. Si este no es el caso, la SecretKey se deberá guardar en un sitio seguro, preferiblemente offline y, si es posible, incluso impresa y almacenada en un lugar protegido. Si esta contraseña se pierde, no es posible iniciar sesión en el servicio.
Como segundo componente de la función, HOTP está basado en un contador que el servidor y el usuario comparten. El problema en este caso es que la contraseña que se genera es válida hasta que se utiliza. TOTP restringe este hecho: el código generado solo se puede utilizar dentro de un periodo de tiempo determinado. Pero ¿cómo funciona?
Hay tres fórmulas relevantes para el algoritmo Time-based-One-time:
TOTP = HOTP(SecretKey,CurrentTime)
Esta sencilla fórmula se limita a especificar que TOTP es un procedimiento HOTP con dos parámetros, SecretKey y CurrentTime:
- SecretKey: contraseña creada de manera aleatoria conocida tanto por el servidor como por el cliente.
- CurrentTime: momento actual en tiempo Unix.
No obstante, la indicación del tiempo varía cada segundo. Y un segundo no es suficiente para transmitir el código a la aplicación. Es decir, el TOTP ya no sería válido pasado un segundo, puesto que el servidor ya habría generado un nuevo valor hash. Por este motivo, se recurre a una fórmula adicional:
CurrentTime = floor((unixtime(now) – unixtime(T0))/T1)
El parámetro CurrentTime se define por lo tanto de la siguiente manera:
- unixtime(now): momento actual en tiempo Unix.
- unixtime(T0): tiempo Unix en el momento T0 a partir del que se cuenta, en la mayoría de los casos es el 01.01.1970 a medianoche (= 0).
- T1: intervalo en el que el TOTP debe ser válido, generalmente 30 segundos.
- floor: función de redondeo para convertir el valor calculado en un número entero.
En teoría, también se puede seleccionar otro valor diferente a 0 para T0. Lo único importante es que el cliente y el servidor seleccionen el mismo valor.
La división y el redondeo generan el efecto de que el resultado varía en intervalos.
A continuación, el valor hash generado se acorta para que resulte más fácil para el usuario:
Result = TOTPmod10d
Con el cálculo Módulo se genera una suma de verificación:
- mod 10: módulo con divisor 10
- d: número de cifras que el TOTP debe tener
De esta forma, la base 10 se eleva a la potencia de las cifras que debe tener el código, se divide el TOTP por este valor y se extrae el resto.
El cálculo de TOTP en un ejemplo
Supongamos que se desea crear un TOTP con una validez de 30 segundos. De esta forma ya podemos calcular el CurrentTime e identificar cómo se va a garantizar el periodo de validez. A modo de unixtime(now) tomamos 1548322860, esto es, el 24.01.2019 a las 10:41 h. Si dividimos esta cifra entre 30, obtenemos exactamente 51610762. Dado que ya se trata de un número entero, tras el redondeo también se obtiene este resultado. Si ahora ajustamos la hora actual 15 segundos más tarde, es decir, 1548322875, tras la división obtenemos 51610762,5 como resultado. También se redondea a 51610762. El CurrentTime permanece por lo tanto igual. En la siguiente tabla se puede observar que, al cabo de 30 segundos, se genera un nuevo valor:
unixtime(now) | unixtime(now)/30 | floor(unixtime(now)/30) |
---|---|---|
1548322857 | 51610761,9000 | 51610761 |
1548322858 | 51610761,9333 | 51610761 |
1548322859 | 51610761,9667 | 51610761 |
1548322860 | 51610762,0000 | 51610762 |
1548322861 | 51610762,0333 | 51610762 |
1548322862 | 51610762,0667 | 51610762 |
1548322863 | 51610762,1000 | 51610762 |
1548322864 | 51610762,1333 | 51610762 |
1548322865 | 51610762,1667 | 51610762 |
1548322866 | 51610762,2000 | 51610762 |
1548322867 | 51610762,2333 | 51610762 |
1548322868 | 51610762,2667 | 51610762 |
1548322869 | 51610762,3000 | 51610762 |
1548322870 | 51610762,3333 | 51610762 |
1548322871 | 51610762,3667 | 51610762 |
1548322872 | 51610762,4000 | 51610762 |
1548322873 | 51610762,4333 | 51610762 |
1548322874 | 51610762,4667 | 51610762 |
1548322875 | 51610762,5000 | 51610762 |
1548322876 | 51610762,5333 | 51610762 |
1548322877 | 51610762,5667 | 51610762 |
1548322878 | 51610762,6000 | 51610762 |
1548322879 | 51610762,6333 | 51610762 |
1548322880 | 51610762,6667 | 51610762 |
1548322881 | 51610762,7000 | 51610762 |
1548322882 | 51610762,7333 | 51610762 |
1548322883 | 51610762,7667 | 51610762 |
1548322884 | 51610762,8000 | 51610762 |
1548322885 | 51610762,8333 | 51610762 |
1548322886 | 51610762,8667 | 51610762 |
1548322887 | 51610762,9000 | 51610762 |
1548322888 | 51610762,9333 | 51610762 |
1548322889 | 51610762,9667 | 51610762 |
1548322890 | 51610763,0000 | 51610763 |
1548322891 | 51610763,0333 | 51610763 |
El CurrentTime queda por lo tanto fijado (51610762). La SecretKey se obtiene por medio de un generador de contraseñas: >cHSB_UQ#O5m;~b
HMAC con SHA-1 forma un valor hash (en notación hexadecimal) a partir de la contraseña y la hora: c0 62 37 94 dd 37 7a 3a f0 91 22 08 1f 21 6f 9b 17 4b 17 45. Este valor de 160 bits o 20 bytes de largo se reduce a 31 bits por medio de la denominada dynamic truncation. Para ello, se consideran en primer lugar los últimos 4 bits, es decir, la cifra 0x5, que también se escribe como 5 en notación decimal. Esto se corresponde con el valor de desplazamiento de la dynamic truncation y significa que, a partir del byte con el índice 5 (desde la izquierda comenzando por 0), se extraen cuatro bytes: 0x377a3af0. En este caso, el valor comienza con un bit que está en 0. Si este no fuera el caso, se modificará correspondientemente. Por lo tanto, el valor con una longitud de 31 bits es también 0x377a3af0 o 930757360.
Para reducir esta secuencia de nueve cifras a seis, se utiliza una operación módulo y, en caso necesario, se rellena a la izquierda con ceros: 930757360 mod (106) = 757360. Este es el TOTP que tendrá validez durante 30 segundos. En combinación con otro factor se consigue un procedimiento de inicio de sesión bastante seguro.