Senhas de Uso Único

HOTP e TOTP são os códigos que um aplicativo autenticador de celular mostra. As duas funções vivem em sgcCrypto_OTP e são construídas sobre HMAC (veja Hashing & Autenticação de Mensagens).

 

HOTP (baseado em contador)

 

O código depende de um segredo compartilhado e de um contador que avança de um em um a cada uso. O cliente e o servidor precisam permanecer sincronizados: se o cliente gerar códigos que o servidor nunca vê (um botão pressionado sem conexão de rede, por exemplo), os contadores se desalinham e todo código que o cliente mostrar depois falha até o servidor ressincronizar. Essa deriva é o principal motivo pelo qual o TOTP substituiu o HOTP na maioria dos usos de autenticador para consumidores.

 


function sgcHOTP(const aSecret: TBytes; aCounter: Int64; aDigits: Integer = 6): string;

 

TOTP (baseado em tempo)

 

O contador do HOTP é substituído pelo tempo Unix atual dividido em passos fixos, 30 segundos por padrão, de modo que o cliente e o servidor só precisam de relógios aproximadamente sincronizados em vez de um contador sincronizado. É isso que todo aplicativo autenticador implementa.

 


function sgcTOTP(const aSecret: TBytes; aUnixTime: Int64; aDigits: Integer = 6;
  aStep: Integer = 30; aHash: TsgcKDFHash = khSHA1): string;

{ Takes the base32 secret exactly as an authenticator app displays or scans it. }
function sgcTOTP_FromBase32(const aSecretBase32: string; aUnixTime: Int64;
  aDigits: Integer = 6; aStep: Integer = 30; aHash: TsgcKDFHash = khSHA1): string;

 

Verificando um código

 

aWindow aceita códigos de tantos passos antes e depois do atual, o que absorve uma pequena diferença de relógio ou um usuário que demorou para digitar o código. A comparação é internamente em tempo constante, portanto não vaza quantos dígitos de um palpite estavam corretos.

 


function sgcTOTP_Verify(const aSecret: TBytes; const aCode: string; aUnixTime: Int64;
  aWindow: Integer = 1; aDigits: Integer = 6; aStep: Integer = 30; aHash: TsgcKDFHash = khSHA1): Boolean;

var
  oSecret: TBytes;
begin
  oSecret := sgcRandomBytes(20);
  if sgcTOTP_Verify(oSecret, edtCode.Text, DateTimeToUnix(Now, False)) then
    { accepted };
end;

 

Provisionando um segredo

 

Um aplicativo autenticador é configurado escaneando um código QR que codifica uma URI otpauth://. O segredo dentro dela é codificado em base32 (veja sgcBase32Encode na página de visão geral Criptografia):

 


var
  oSecret: TBytes;
  vURI: string;
begin
  oSecret := sgcRandomBytes(20);
  vURI := 'otpauth://totp/MyApp:user@example.com?secret=' + sgcBase32Encode(oSecret) +
    '&issuer=MyApp&digits=6&period=30';
  { render vURI as a QR code for the user to scan }
end;