Contraseñas de un Solo Uso

HOTP y TOTP son los códigos que muestra una aplicación autenticadora de teléfono. Ambas funciones residen en sgcCrypto_OTP y se construyen sobre HMAC (vea Hash y Autenticación de Mensajes).

 

HOTP (basado en contador)

 

El código depende de un secreto compartido y de un contador que avanza en uno con cada uso. El cliente y el servidor deben mantenerse sincronizados: si el cliente genera códigos que el servidor nunca ve (por ejemplo, un botón pulsado sin conexión de red), los contadores se desalinean y todos los códigos que el cliente muestre después fallan hasta que el servidor se resincronice. Esa desalineación es el motivo principal por el que TOTP sustituyó a HOTP en la mayoría de los usos de autenticadores de consumo.

 


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

 

TOTP (basado en tiempo)

 

El contador de HOTP se sustituye por el tiempo Unix actual dividido en pasos fijos, 30 segundos por defecto, de modo que el cliente y el servidor solo necesitan relojes aproximadamente sincronizados en lugar de un contador sincronizado. Esto es lo que implementa cualquier aplicación autenticadora.

 


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;

 

Verificar un código

 

aWindow acepta códigos de ese número de pasos antes y después del actual, lo que absorbe un pequeño desfase de reloj o un usuario que tardó en escribir el código. La comparación es internamente en tiempo constante, de modo que no filtra cuántos dígitos de una suposición eran correctos.

 


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;

 

Aprovisionar un secreto

 

Una aplicación autenticadora se configura escaneando un código QR que codifica una URI otpauth://. El secreto dentro de ella está codificado en base32 (vea sgcBase32Encode en la página general de Criptografía):

 


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;