function TForm1.GenerateBase32Secret(ALength: Integer):
string;
const
Alphabet = '
ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
var
i: Integer;
begin
Randomize;
Result := '
';
for i := 1
to ALength
do
Result := Result + Alphabet[Random(Length(Alphabet)) + 1];
end;
function TForm1.BuildOtpAuthURI(
const User, Issuer, Secret:
string):
string;
begin
Result := Format(
'
otpauth://totp/%s:%s?secret=%s&issuer=%s&digits=6&period=30',
[Issuer, User, Secret, Issuer]);
end;
procedure TForm1.GenerateQRCode(
const Text:
string; Bitmap: TBitmap);
var
QRCode: TDelphiZXingQRCode;
x, y: Integer;
Scale: Integer;
begin
QRCode := TDelphiZXingQRCode.Create;
try
QRCode.Data := Text;
Scale := 5;
Bitmap.SetSize(QRCode.Rows * Scale, QRCode.Columns * Scale);
Bitmap.Canvas.Brush.Color := clWhite;
Bitmap.Canvas.FillRect(Rect(0, 0, Bitmap.Width, Bitmap.Height));
for y := 0
to QRCode.Rows - 1
do
for x := 0
to QRCode.Columns - 1
do
if QRCode.IsBlack[y, x]
then
begin
Bitmap.Canvas.Brush.Color := clBlack;
Bitmap.Canvas.FillRect(Rect(x*Scale, y*Scale,
(x+1)*Scale, (y+1)*Scale));
end;
finally
QRCode.Free;
end;
end;
function TForm1.GenerateTOTP(
const Secret:
string; TimeStep: Int64):
string;
var
Counter: Int64;
Msg, Hash: TBytes;
Offset, Binary, Code: Integer;
begin
Counter := DateTimeToUnix(Now)
div TimeStep;
SetLength(Msg, 8);
PInt64(@Msg[0])^ := Swap(Counter);
// BigEndian
Hash := THashSHA1.GetHMACAsBytes(Msg, TEncoding.ASCII.GetBytes(Secret));
Offset := Hash[High(Hash)]
and $0F;
Binary := ((Hash[Offset]
and $7F)
shl 24)
or
((Hash[Offset+1]
and $FF)
shl 16)
or
((Hash[Offset+2]
and $FF)
shl 8)
or
(Hash[Offset+3]
and $FF);
Code := Binary
mod 1000000;
Result := Format('
%.6d', [Code]);
end;
procedure TForm1.btnGenerate1Click(Sender: TObject);
var
URI:
string;
bmp: TBitmap;
begin
FSecret := GenerateBase32Secret;
URI := BuildOtpAuthURI('
user@example.com', '
MeineApp', FSecret);
bmp := TBitmap.Create;
try
GenerateQRCode(
URI, bmp);
imgQR.Picture.Assign(bmp);
finally
bmp.Free;
end;
lblResult.Caption := '
QR-Code erzeugt. Bitte mit Authenticator scannen.';
end;
procedure TForm1.btnVerifyClick(Sender: TObject);
var
Code:
string;
begin
Code := GenerateTOTP(FSecret);
if edtCode.Text = Code
then
lblResult.Caption := '
✅ Code korrekt!'+Code
else
lblResult.Caption := '
❌ Ungültiger Code'+Code;
end;