HOTP e TOTP sono i codici mostrati da un'app di autenticazione sul telefono. Entrambe le funzioni risiedono in sgcCrypto_OTP e sono costruite su HMAC (vedere Hashing e autenticazione dei messaggi).
HOTP (basato su contatore)
Il codice dipende da un segreto condiviso e da un contatore che avanza di uno a ogni utilizzo. Il client e il server devono restare sincronizzati: se il client genera codici che il server non vede mai (ad esempio un pulsante premuto senza connessione di rete), i contatori si disallineano e ogni codice mostrato successivamente dal client fallisce finché il server non si risincronizza. Questo disallineamento è il motivo principale per cui TOTP ha sostituito HOTP nella maggior parte degli usi consumer di autenticazione.
function sgcHOTP(const aSecret: TBytes; aCounter: Int64; aDigits: Integer = 6): string;
TOTP (basato sul tempo)
Il contatore di HOTP viene sostituito dall'ora Unix corrente suddivisa in step fissi, 30 secondi per default, in modo che il client e il server abbiano bisogno solo di orologi approssimativamente sincronizzati anziché di un contatore sincronizzato. Questo è ciò che implementa ogni app di autenticazione.
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;
Verifica di un codice
aWindow accetta codici da quel numero di step prima e dopo quello corrente, il che assorbe un piccolo scarto dell'orologio o un utente che ha impiegato tempo a digitare il codice. Il confronto è internamente a tempo costante, quindi non rivela quante cifre di un tentativo fossero corrette.
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;
Provisioning di un segreto
Un'app di autenticazione viene configurata scansionando un codice QR che codifica una URI otpauth://. Il segreto al suo interno è codificato in base32 (vedere sgcBase32Encode nella pagina panoramica Crittografia):
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;