OpenPGP in Delphi: cifrare, firmare e verificare senza GnuPG

· Componenti
OpenPGP in Delphi: cifrare, firmare e verificare senza GnuPG

OpenPGP è ancora il modo in cui molte organizzazioni si scambiano i file. Una banca vuole lotti di pagamenti cifrati con la sua chiave pubblica, un partner invia report cifrati con GnuPG, una release deve essere distribuita con una firma detached. Da Delphi questo significava di solito installare GnuPG su ogni macchina e chiamare gpg.exe da riga di comando, con tutta la gestione di percorsi, keyring e codici di uscita che ne consegue.

sgcCrypto ora implementa OpenPGP in autonomia, in puro Object Pascal. Non c'è nessuna DLL da distribuire, nessuno strumento da riga di comando da chiamare e nessuna dipendenza da Indy. Chiavi, cifratura, decifratura, firme e verifica si riducono a una manciata di chiamate a funzione su TBytes, e il risultato interopera con GnuPG in entrambe le direzioni.

Versione 4 e versione 6

Sono supportate due generazioni del formato:

Quando cifri per più destinatari, la libreria sceglie il formato che tutti possono leggere: il formato AEAD della RFC 9580 se lo supportano tutti, altrimenti il classico formato con protezione dell'integrità. Un messaggio destinato a un insieme di chiavi vecchie e nuove si apre comunque ovunque.

Generare una chiave

Una sola chiamata crea una chiave completa: una chiave primaria di firma, una sottochiave di cifratura, lo user ID e le autofirme che li legano insieme.

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;

I tipi di chiave sono RSA 2048, 3072 e 4096, Ed25519, Ed448 (versione 6) ed ECDSA con ECDH su NIST P-256, P-384 e P-521. Le chiavi Brainpool possono essere importate. Le chiavi segrete sono protette con la tua passphrase, usando SHA-256 iterato per la versione 4 e Argon2 con AES-OCB per la versione 6.

Cifrare e decifrare

Cifra per una o più chiavi pubbliche, con firma facoltativa del mittente. L'output è in ASCII armor per impostazione predefinita, pronto da allegare a una mail o da caricare su un server.

// 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');

La decifratura richiede un keyring con le tue chiavi segrete. Una chiave bloccata viene sbloccata su una copia privata con la passphrase, quindi il keyring stesso non cambia mai. Il risultato ti dice a chi era destinato il messaggio, come è stato cifrato e se la firma al suo interno è valida.

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;

Firmare e verificare

Sono supportate le firme detached per file e release, i messaggi firmati inline e le firme in chiaro (cleartext) per i testi che devono restare leggibili, con la modalità testo per firme indipendenti dalla codifica di fine riga.

// 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);

Funziona con GnuPG

Ogni funzionalità è stata testata in entrambe le direzioni con GnuPG 2.4.5: i file e le firme creati da GnuPG si decifrano e si verificano in Delphi, e tutto ciò che la libreria produce viene accettato da gpg --decrypt e gpg --verify. Questo include i messaggi cifrati con OCB che GnuPG 2.4 scrive per impostazione predefinita per le chiavi che ha generato, e che molte librerie OpenPGP non sono in grado di leggere. Il supporto alla versione 6 è stato verificato con le chiavi e i messaggi di esempio della RFC 9580.

Le chiavi passano da un mondo all'altro come testo armored. Esporta una chiave da Delphi ed esegui gpg --import, oppure carica l'output di gpg --export --armor in un TsgcPGPKeyRing.

Pensato per input non attendibili

Un'applicazione che decifra file provenienti dall'esterno deve presumere che alcuni di essi siano ostili. La libreria rifiuta il vecchio formato di cifratura senza protezione, segnala ogni errore di decifratura con lo stesso errore in modo che non possa essere usato come oracolo, rifiuta le firme SHA-1 sui documenti e impone limiti ai fattori di lavoro delle passphrase e alla dimensione decompressa, così un messaggio costruito ad arte non può bloccare il server.

Cos'altro c'è di nuovo

Le unit OpenPGP compilano con Delphi 7 fino a Delphi 13 e con C++Builder, per Win32 e Win64. Le chiavi DSA ed ElGamal possono essere caricate ma non usate, e i vecchi cifrari CAST5, 3DES e IDEA non sono supportati.

Continua a leggere

Domande su un'integrazione specifica, un formato bancario o una chiave che devi importare? Mettiti in contatto. Riceverai una risposta dalle persone che hanno scritto il codice.