OpenPGP in Delphi: verschlüsseln, signieren und prüfen ohne GnuPG

· Komponenten
OpenPGP in Delphi: verschlüsseln, signieren und prüfen ohne GnuPG

OpenPGP ist für viele Organisationen noch immer der Weg, Dateien auszutauschen. Eine Bank möchte Zahlungsstapel mit ihrem öffentlichen Schlüssel verschlüsselt erhalten, ein Partner sendet mit GnuPG verschlüsselte Berichte, ein Release muss mit einer losgelösten Signatur ausgeliefert werden. Aus Delphi bedeutete das meist, GnuPG auf jedem Rechner zu installieren und gpg.exe von einer Kommandozeile aufzurufen, samt aller Pfad-, Schlüsselbund- und Exit-Code-Behandlung, die dazugehört.

sgcCrypto implementiert OpenPGP jetzt selbst, in reinem Object Pascal. Es gibt keine DLL auszuliefern, kein Kommandozeilenwerkzeug aufzurufen und keine Abhängigkeit von Indy. Schlüssel, Verschlüsselung, Entschlüsselung, Signaturen und Prüfung sind eine Handvoll Funktionsaufrufe auf TBytes, und das Ergebnis arbeitet in beide Richtungen mit GnuPG zusammen.

Version 4 und Version 6

Zwei Generationen des Formats werden unterstützt:

Wenn Sie an mehrere Empfänger verschlüsseln, wählt die Bibliothek das Format, das jeder von ihnen lesen kann: das AEAD-Format von RFC 9580, wenn alle es unterstützen, sonst das klassische integritätsgeschützte Format. Eine Nachricht an eine Mischung aus alten und neuen Schlüsseln lässt sich überall öffnen.

Einen Schlüssel erzeugen

Ein Aufruf erzeugt einen vollständigen Schlüssel: einen primären Signaturschlüssel, einen Verschlüsselungs-Subschlüssel, die User-ID und die Selbstsignaturen, die sie miteinander verbinden.

uses
  sgcCrypto_PGP, sgcCrypto_PGP_Cert;

var
  oAlice: TsgcPGPKey;
begin
  // v4 Ed25519 + Curve25519, the default key type of GnuPG
  oAlice := sgcPGP_GenerateKey('Alice <alice@example.com>', 'secret',
    pgpkEd25519, 4);
  try
    Memo1.Text := oAlice.SaveToArmored(False);  // public key, share it
    SaveSecretKey(oAlice.SaveToArmored(True));  // protected secret key
  finally
    oAlice.Free;
  end;
end;

Als Schlüsseltypen stehen RSA 2048, 3072 und 4096, Ed25519, Ed448 (Version 6) sowie ECDSA mit ECDH auf NIST P-256, P-384 und P-521 zur Verfügung. Brainpool-Schlüssel können importiert werden. Geheime Schlüssel werden mit Ihrer Passphrase geschützt, bei Version 4 mit iteriertem SHA-256 und bei Version 6 mit Argon2 und AES-OCB.

Verschlüsseln und entschlüsseln

Verschlüsseln Sie an einen oder mehrere öffentliche Schlüssel, optional vom Absender signiert. Die Ausgabe ist standardmäßig ASCII-armiert und damit bereit, an eine Mail angehängt oder auf einen Server hochgeladen zu werden.

// encrypt to Bob, signed by Alice, compressed with ZIP
vEncrypted := sgcPGP_Encrypt(vData, [oBob], oAlice);

// or protect a file with a passphrase only
vEncrypted := sgcPGP_EncryptSymmetric(vData, 'shared passphrase');

Die Entschlüsselung benötigt einen Schlüsselbund mit Ihren geheimen Schlüsseln. Ein gesperrter Schlüssel wird mit der Passphrase auf einer privaten Kopie entsperrt, sodass sich der Schlüsselbund selbst nie ändert. Das Ergebnis sagt Ihnen, für wen die Nachricht bestimmt war, wie sie verschlüsselt wurde und ob die darin enthaltene Signatur gültig ist.

var
  oRing: TsgcPGPKeyRing;
  vResult: TsgcPGPDecryptResult;
begin
  oRing := TsgcPGPKeyRing.Create;
  try
    oRing.LoadFromFile('bob-secret.asc');
    vData := sgcPGP_Decrypt(vEncrypted, oRing, 'bob passphrase', oContacts,
      vResult);
    if vResult.Verify.Valid then
      Log('Signed by ' + vResult.Verify.SignerUserID);
  finally
    oRing.Free;
  end;
end;

Signieren und prüfen

Losgelöste Signaturen für Dateien und Releases, inline signierte Nachrichten und Klartextsignaturen für Text, der lesbar bleiben muss, werden alle unterstützt, mit Textmodus für zeilenumbruchunabhängige Signaturen.

// detached signature, the classic file.sig
vSignature := sgcPGP_Sign(vData, oAlice);
if sgcPGP_VerifyDetached(vData, vSignature, oContacts, vVerify) then
  Log('Valid signature from ' + vVerify.SignerUserID);

// cleartext signed text, readable without any tool
vSigned := sgcPGP_ClearSign('Payment batch 2026-10 approved', oAlice);

Funktioniert mit GnuPG

Jede Funktion wurde in beide Richtungen gegen GnuPG 2.4.5 getestet: Dateien und Signaturen von GnuPG lassen sich in Delphi entschlüsseln und prüfen, und alles, was die Bibliothek erzeugt, wird von gpg --decrypt und gpg --verify akzeptiert. Dazu gehören die OCB-verschlüsselten Nachrichten, die GnuPG 2.4 für selbst erzeugte Schlüssel standardmäßig schreibt und die viele OpenPGP-Bibliotheken nicht lesen können. Die Unterstützung für Version 6 wurde anhand der Beispielschlüssel und -nachrichten von RFC 9580 geprüft.

Schlüssel wandern als armierter Text zwischen beiden Welten. Exportieren Sie einen Schlüssel aus Delphi und führen Sie gpg --import aus, oder laden Sie die Ausgabe von gpg --export --armor in einen TsgcPGPKeyRing.

Gebaut für nicht vertrauenswürdige Eingaben

Eine Anwendung, die Dateien von außen entschlüsselt, muss davon ausgehen, dass einige davon bösartig sind. Die Bibliothek lehnt das alte ungeschützte Verschlüsselungsformat ab, meldet jeden Entschlüsselungsfehler mit demselben Fehler, damit er nicht als Orakel missbraucht werden kann, weist SHA-1-Signaturen auf Dokumenten zurück und setzt Grenzen für den Aufwand bei Passphrasen und für die dekomprimierte Größe, damit eine präparierte Nachricht den Server nicht lahmlegen kann.

Was es sonst noch Neues gibt

Die OpenPGP-Units lassen sich mit Delphi 7 bis Delphi 13 und C++Builder für Win32 und Win64 kompilieren. DSA- und ElGamal-Schlüssel können geladen, aber nicht verwendet werden, und die alten Chiffren CAST5, 3DES und IDEA werden nicht unterstützt.

Als Nächstes lesen

Fragen zu einer konkreten Integration, einem Bankformat oder einem Schlüssel, den Sie importieren müssen? Nehmen Sie Kontakt auf. Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.