Einmalpasswörter

HOTP und TOTP sind die Codes, die eine Authenticator-App auf dem Telefon anzeigt. Beide Funktionen befinden sich in sgcCrypto_OTP und bauen auf HMAC auf (siehe Hashing & Nachrichtenauthentifizierung).

 

HOTP (zählerbasiert)

 

Der Code hängt von einem gemeinsamen Geheimnis und einem Zähler ab, der bei jeder Verwendung um eins erhöht wird. Client und Server müssen synchron bleiben: Wenn der Client Codes erzeugt, die der Server nie sieht (zum Beispiel ein Knopfdruck ohne Netzwerkverbindung), driften die Zähler auseinander, und jeder danach vom Client angezeigte Code schlägt fehl, bis der Server sich neu synchronisiert. Dieses Driften ist der Hauptgrund, warum TOTP HOTP für die meisten Consumer-Authenticator-Anwendungen abgelöst hat.

 


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

 

TOTP (zeitbasiert)

 

Der Zähler in HOTP wird durch die aktuelle Unix-Zeit ersetzt, unterteilt in feste Schritte, standardmäßig 30 Sekunden, sodass Client und Server nur ungefähr synchronisierte Uhren statt eines synchronisierten Zählers benötigen. Das ist es, was jede Authenticator-App implementiert.

 


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;

 

Einen Code verifizieren

 

aWindow akzeptiert Codes aus so vielen Schritten vor und nach dem aktuellen, was eine kleine Uhrenabweichung oder einen Benutzer abfedert, der den Code langsam eingegeben hat. Der Vergleich ist intern konstant in der Zeit, sodass er nicht preisgibt, wie viele Stellen eines Rateversuchs korrekt waren.

 


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;

 

Ein Geheimnis provisionieren

 

Eine Authenticator-App wird eingerichtet, indem ein QR-Code gescannt wird, der eine otpauth://-URI kodiert. Das darin enthaltene Geheimnis ist base32-kodiert (siehe sgcBase32Encode auf der Übersichtsseite Kryptografie):

 


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;