PureTools

TOTP: Como a Autenticação em Dois Fatores Realmente Funciona

PureTools Team· 10 min de leitura
TOTP: Como a Autenticação em Dois Fatores Realmente Funciona

TOTP: Aqueles Códigos de 6 Dígitos Não São Mágica

A cada 30 segundos, seu app autenticador gera um novo código de 6 dígitos. Sem conexão com internet. Sem comunicação com servidor. Como o servidor sabe qual código você está vendo? Porque ambos os lados estão rodando o mesmo algoritmo com o mesmo segredo.

O Algoritmo

TOTP (Time-Based One-Time Password, RFC 6238) funciona em 4 passos:

  1. Pegar o tempo atual como timestamp Unix
  2. Dividir pelo time step (30 segundos por padrão) → isso dá um valor de contador
  3. HMAC-SHA1 do contador com o segredo compartilhado → produz um hash de 20 bytes
  4. Truncar o hash para um número de 6 dígitos
// Pseudocódigo
time_step = floor(unix_timestamp / 30)
hmac = HMAC-SHA1(secret, time_step)
offset = hmac[19] & 0x0f
code = (hmac[offset..offset+3] & 0x7fffffff) % 1000000
// Resultado: código de 6 dígitos como "482901"

Por Que Funciona Sem Internet

Durante o setup, o servidor gera um segredo aleatório e compartilha com seu autenticador (via QR code). Ambos os lados agora têm:

  • O mesmo segredo (tipicamente 20 bytes, codificado em Base32)
  • O mesmo algoritmo (HMAC-SHA1)
  • O mesmo time step (30 segundos)
  • Relógios sincronizados (dentro de tolerância razoável)

O servidor não precisa contatar seu celular. Ele apenas roda o mesmo cálculo com o mesmo segredo e verifica se os códigos batem.

O QR Code

Quando você escaneia um QR code TOTP, ele contém uma URI como:

otpauth://totp/MyApp:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp&algorithm=SHA1&digits=6&period=30
ParâmetroValorSignificado
secretJBSWY3DPEHPK3PXPSegredo compartilhado codificado em Base32
issuerMyAppNome do serviço mostrado no autenticador
algorithmSHA1Algoritmo HMAC (SHA1/SHA256/SHA512)
digits6Tamanho do código (6 ou 8)
period30Time step em segundos

Implementação em JavaScript

// Verificação TOTP em Node.js
import { createHmac } from 'crypto';

function generateTOTP(secret: Buffer, timeStep = 30): string {
  const counter = Math.floor(Date.now() / 1000 / timeStep);

  // Converter contador para buffer big-endian de 8 bytes
  const counterBuffer = Buffer.alloc(8);
  counterBuffer.writeBigInt64BE(BigInt(counter));

  // HMAC-SHA1
  const hmac = createHmac('sha1', secret).update(counterBuffer).digest();

  // Truncamento dinâmico
  const offset = hmac[hmac.length - 1] & 0x0f;
  const code = (
    ((hmac[offset] & 0x7f) << 24) |
    ((hmac[offset + 1] & 0xff) << 16) |
    ((hmac[offset + 2] & 0xff) << 8) |
    (hmac[offset + 3] & 0xff)
  ) % 1000000;

  return code.toString().padStart(6, '0');
}

// Verificar com janela ±1 para drift de relógio
function verifyTOTP(secret: Buffer, token: string): boolean {
  for (let i = -1; i <= 1; i++) {
    const adjustedTime = Date.now() + i * 30000;
    // ... gerar código no tempo ajustado
    if (generatedCode === token) return true;
  }
  return false;
}

Implementação Python

import hmac
import hashlib
import struct
import time
import base64

def generate_totp(secret_b32: str, time_step: int = 30) -> str:
    secret = base64.b32decode(secret_b32)
    counter = int(time.time()) // time_step
    counter_bytes = struct.pack('>Q', counter)

    hmac_hash = hmac.new(secret, counter_bytes, hashlib.sha1).digest()

    offset = hmac_hash[-1] & 0x0f
    code = (
        struct.unpack('>I', hmac_hash[offset:offset + 4])[0] & 0x7fffffff
    ) % 1000000

    return f"{code:06d}"

# Exemplo
print(generate_totp('JBSWY3DPEHPK3PXP'))
# "482901" (muda a cada 30 segundos)

Considerações de Segurança

  • Armazene segredos criptografados. O segredo TOTP no seu banco de dados é equivalente a uma senha. Criptografe em repouso.
  • Forneça códigos de backup. Usuários perdem celulares. Gere 8-10 códigos de uso único durante o setup.
  • Permita drift de relógio. Aceite códigos do time step anterior e próximo (±30 segundos).
  • Rate limit na verificação. Sem rate limiting, um atacante tem 1/1.000.000 de chance por tentativa — brute-forceable em alta velocidade.
  • Não use SMS. TOTP (app autenticador) é mais seguro que 2FA baseado em SMS, que é vulnerável a SIM swapping.

TOTP vs HOTP

FeatureTOTP (Baseado em Tempo)HOTP (Baseado em Contador)
ContadorTempo atual / 30Inteiro incrementado
ExpiraçãoCódigos expiram após 30sCódigos nunca expiram
Problemas de syncDrift de relógioDesync de contador
SegurançaMelhor (códigos expiram)Menos seguro (replay possível)
Usado porGoogle Authenticator, AuthyYubiKey (modo HOTP), alguns tokens físicos

Gere códigos TOTP: Gerador TOTP — insira uma chave secreta e veja o código ao vivo com timer de contagem regressiva.