OpenPGP, PGP ve GnuPG'nin arkasındaki standarttır. Dosyaları ve mesajları bir veya daha fazla kişiye şifreler, alıcının bunları kimin yazdığını ve hiçbir şeyin değiştirilmediğini doğrulayabilmesi için imzalar ve her ikisini de bir sertifika otoritesi olmadan yapar: her kullanıcı bir anahtar çiftine sahiptir ve genel yarısını yayımlar. Şifreli e-posta, imzalı yazılım sürümleri, paket depoları ve iş ortakları ile bankalarla dosya alışverişi için kullanılan biçimdir.
sgcCrypto birimleri OpenPGP'yi saf Object Pascal ile uygular; harici DLL, OpenSSL ve Indy gerektirmez. Win32 ve Win64 üzerinde Delphi 7'den Delphi 13'e kadar derlenir ve birimler Linux64 için de derlenir. Her şey bellekte TBytes üzerinde çalışır: armor'lu çıktı, TBytes olarak döndürülen ASCII metindir ve sgcPGP_UTF8 ile sgcPGP_UTF8ToString yardımcıları dizeler ile baytlar arasında dönüştürme yapar.
Sürüm 4 veya sürüm 6
Biçimin iki sürümü desteklenir ve her ikisi de okunur ve yazılır.
Sürüm 4 (RFC 4880 ve RFC 6637), GnuPG, Kleopatra, Thunderbird ve bugün dağıtılmış hemen her aracın kullandığı sürümdür. Karşı taraf GnuPG çalıştırıyorsa veya yazılımlarını kontrol etmiyorsanız bunu seçin. Mesajlar SEIPD v1 ile korunur (CFB modunda AES ve bir MDC bütünlük denetimi).
Sürüm 6 (RFC 9580), standardın güncel revizyonudur. Anahtarlar doğrudan Ed25519/X25519 veya Ed448/X448 kullanır, gizli anahtarlar Argon2 ile korunur ve mesajlar gerçek bir AEAD yapısı olan SEIPD v2'yi (varsayılan olarak OCB) kullanır. Tüm taraflar RFC 9580'i destekliyorsa, örneğin kendi geliştirdiğiniz iki uygulama arasında, bunu seçin. GnuPG 2.4 v6 anahtarlarını okumaz.
Her mesaj için seçim yapmanız gerekmez. Şifrelerken SEIPD v2 yalnızca tüm alıcılar bunu destekliyorsa (v6 anahtarlar) kullanılır. Alıcılardan birinin v4 anahtarı varsa mesaj SEIPD v1 olarak yazılır, böylece karma bir alıcı listesi GnuPG tarafından okunabilir kalır.
Desteklenen özellikler
| Alan | Desteklenen |
| Biçimler | OpenPGP v4 (RFC 4880, RFC 6637, GnuPG uyumlu) ve v6 (RFC 9580) |
| Açık anahtar algoritmaları | RSA 2048/3072/4096, Ed25519, Ed448 (yalnızca v6), X25519, X448, NIST P-256/P-384/P-521 üzerinde ECDSA ve ECDH, Brainpool eğrileri üzerinde ECDSA ve ECDH (yalnızca içe aktarma) |
| Simetrik şifreler | AES-128, AES-192, AES-256 |
| Şifreli veri | SEIPD v1 (CFB artı MDC), OCB, EAX veya GCM ile SEIPD v2 AEAD |
| Oturum anahtarları | Açık anahtar (PKESK v3 ve v6) ve parola (SKESK v4 ve v6) |
| Anahtar koruması (S2K) | Yinelemeli ve tuzlu S2K, Argon2 S2K |
| Sıkıştırma | ZIP (ham DEFLATE) ve ZLIB |
| İmzalar | Ayrık (detached), satır içi (tek geçiş) ve açık metin (cleartext) imzaları, ikili ve metin modu |
| Kodlama | ASCII armor ve ikili |
| GnuPG 2.4 LibrePGP | OCB şifreli mesajları (paket 20) ve v5 SKESK paketlerini okur, hiçbir zaman yazmaz |
Birimler
| Birim | İçerik |
| sgcCrypto_PGP | Üst düzey API: şifreleme, şifre çözme, imzalama, doğrulama, sonuç kayıtları |
| sgcCrypto_PGP_Cert | Aktarılabilir anahtarlar, anahtar halkaları ve anahtar üretimi: TsgcPGPKey, TsgcPGPKeyRing, sgcPGP_GenerateKey |
| sgcCrypto_PGP_Message | Mesaj paketleri: oturum anahtarları, şifreli veri, literal ve sıkıştırılmış veri |
| sgcCrypto_PGP_Signature | İmza paketleri, oluşturma ve doğrulama |
| sgcCrypto_PGP_Keys | Anahtar paketleri ve gizli anahtar koruması |
| sgcCrypto_PGP_Packets | Paket çerçeveleme, ASCII armor, S2K, sabitler ve yardımcılar |
| sgcCrypto_Modes | SEIPD v2 tarafından kullanılan AES-OCB ve AES-EAX (bkz. Simetrik Şifreleme) |
| sgcCrypto_Deflate | DEFLATE ve ZLIB sıkıştırması (bkz. WinZip AE-2 Arşiv Şifrelemesi) |
Çoğu uygulamanın uses yan tümcesinde yalnızca sgcCrypto_PGP, sgcCrypto_PGP_Cert ve sgcCrypto_PGP_Packets birimlerine ihtiyacı vardır. Birimler Kriptografi paketinin bir parçasıdır ve FIPS derlemelerinin dışında bırakılır (SGC_CRYPTO_FIPS, bkz. FIPS Modu).
Anahtar yönetimi
sgcPGP_GenerateKey, bir birincil imzalama anahtarı ile bir şifreleme alt anahtarı oluşturur, kullanıcı kimliğini bir öz imza ile bağlar ve bir TsgcPGPKey döndürür. Parola, gizli anahtar kaydedildiğinde onu korur; döndürülen nesnenin kilidi zaten açıktır ve hemen imzalayabilir ve şifre çözebilir. Boş bir parola, gizli anahtarı korumasız kaydeder. aExpirationSeconds, oluşturma anından itibaren sayılan bir anahtar ömrü belirler, 0 anahtarın hiç sona ermediği anlamına gelir.
| TsgcPGPKeyType | Sürüm 4 | Sürüm 6 |
| pgpkEd25519 | EdDSA Ed25519 + ECDH Curve25519 | Ed25519 + X25519 |
| pgpkEd448 | kullanılamaz | Ed448 + X448 |
| pgpkRSA2048 | RSA 2048 | kullanılamaz (RFC 9580 asgari değeri 3072'dir) |
| pgpkRSA3072 | RSA 3072 | RSA 3072 |
| pgpkRSA4096 | RSA 4096 | RSA 4096 |
| pgpkNISTP256 | ECDSA + ECDH P-256 | ECDSA + ECDH P-256 |
| pgpkNISTP384 | ECDSA + ECDH P-384 | ECDSA + ECDH P-384 |
| pgpkNISTP521 | ECDSA + ECDH P-521 | ECDSA + ECDH P-521 |
function sgcPGP_GenerateKey(const aUserID, aPassphrase: string;
aKeyType: TsgcPGPKeyType = pgpkEd25519; aVersion: Integer = 4;
aExpirationSeconds: Cardinal = 0): TsgcPGPKey;
var
oAlice: TsgcPGPKey;
vPublic, vPrivate: string;
begin
oAlice := sgcPGP_GenerateKey('Alice <alice@example.com>', 'alice passphrase',
pgpkEd25519, 4);
try
vPublic := oAlice.SaveToArmored(False); { share this one }
vPrivate := oAlice.SaveToArmored(True); { keep this one, protected by the passphrase }
WriteLn(oAlice.FingerprintHex + ' ' + oAlice.PrimaryUserID);
finally
oAlice.Free;
end;
end;
Bir dosyadan yüklenen anahtar, bir parola ile kaydedilmişse kilitlidir. İmzalamak için kullanmadan önce Unlock çağırın; parola yanlışsa False döndürür. Protect, gizli materyali yeni bir parola ile yeniden şifreler; parolayı bu şekilde değiştirirsiniz. v4 anahtarları AES-256 ve yinelemeli ve tuzlu S2K ile korunur; v6 anahtarları OCB modunda AES-256 ve bir Argon2 S2K ile korunur.
var
oKey: TsgcPGPKey;
begin
oKey := TsgcPGPKey.Create;
try
oKey.LoadFromBytes(sgcPGP_UTF8(vPrivate)); { armored or binary }
if not oKey.Unlock('alice passphrase') then
raise Exception.Create('wrong passphrase');
oKey.Protect('new passphrase');
vPrivate := oKey.SaveToArmored(True);
finally
oKey.Free;
end;
end;
Bir TsgcPGPKeyRing istediği sayıda anahtarı tutar ve onlara sahip olur: Add metoduna verilen bir anahtar halka ile birlikte serbest bırakılır, bu yüzden onu kendiniz serbest bırakmayın. LoadFromFile ve LoadFromBytes, bir veya birçok anahtar içeren armor'lu veya ikili verileri kabul eder (bir GnuPG anahtar halkasının tamamının dışa aktarımı da çalışır) ve zaten yüklenmiş olanlara ekleme yapar. Aramalar:
Her anahtar Version, FingerprintHex, KeyIDHex, PrimaryUserID, HasSecret, IsValid, IsRevoked, IsExpired ve ExpirationTime özelliklerini ve ayrıca kullanıcı kimliklerini ile alt anahtarlarını sunar. Öz imzalar, alt anahtar bağlamaları, sona erme ve iptal yükleme sırasında denetlenir; iptal edilmiş veya süresi dolmuş bir anahtar şifreleme veya imzalama için asla seçilmez.
Şifreleme ve şifre çözme
sgcPGP_Encrypt, bir veya daha fazla açık anahtara şifreler. Bir imzalayıcı verilirse veri şifreli mesajın içinde imzalanır; gpg --sign --encrypt komutunun ürettiği budur. İmzalayıcının kilidi açık olmalıdır. Veri varsayılan olarak ZIP ile sıkıştırılır; bunu değiştirmek için CSGC_PGP_COMP_ZLIB veya CSGC_PGP_COMP_NONE verin. Her alıcı tercihlerinde AES-256'yı listeliyorsa (SEIPD v2 için her zaman) AES-256 kullanılır, aksi halde AES-128.
function sgcPGP_Encrypt(const aData: TBytes;
const aRecipients: array of TsgcPGPKey; aSigner: TsgcPGPKey = nil;
aArmor: Boolean = True; aCompression: Integer = CSGC_PGP_COMP_ZIP;
const aFileName: string = ''): TBytes;
var
oPublicRing: TsgcPGPKeyRing;
oBob: TsgcPGPKey;
oEncrypted: TBytes;
begin
oPublicRing := TsgcPGPKeyRing.Create;
try
oPublicRing.LoadFromFile('public-keys.asc');
oBob := oPublicRing.FindByUserID('bob@example.com');
if oBob = nil then
raise Exception.Create('Bob is not in the keyring');
{ oAlice is an unlocked secret key, used as signer }
oEncrypted := sgcPGP_Encrypt(sgcPGP_UTF8('Hello Bob'), [oBob], oAlice);
WriteLn(sgcPGP_UTF8ToString(oEncrypted)); { -----BEGIN PGP MESSAGE----- }
finally
oPublicRing.Free;
end;
end;
Anahtarlar yerine ortak bir parola için sgcPGP_EncryptSymmetric kullanın. aVersion = 4 ile bir v4 SKESK ve SEIPD v1 yazar; bunu gpg --decrypt okur. 6 ile Argon2'li bir v6 SKESK ve AES-256 OCB'li SEIPD v2 yazar.
function sgcPGP_EncryptSymmetric(const aData: TBytes; const aPassphrase: string;
aArmor: Boolean = True; aVersion: Integer = 4;
aCompression: Integer = CSGC_PGP_COMP_ZIP;
const aFileName: string = ''): TBytes;
oEncrypted := sgcPGP_EncryptSymmetric(sgcPGP_UTF8('Hello'), 'shared passphrase');
sgcPGP_Decrypt her iki türü de, armor'lu veya ikili, işler. aSecretKeys denenecek gizli anahtarları tutar; aPassphrase onların kilidini açar ve ayrıca mesaj parolası olarak denenir. Kilitli bir anahtarın kilidi özel bir kopya üzerinde açılır, bu nedenle verilen anahtar halkası hiçbir zaman değiştirilmez. aVerifyKeys, gömülü bir imzayı denetlemek için kullanılan açık anahtarları tutar ve nil olabilir. Şifresi çözülemeyen bir mesaj EsgcPGPError oluşturur.
function sgcPGP_Decrypt(const aData: TBytes; aSecretKeys: TsgcPGPKeyRing;
const aPassphrase: string; aVerifyKeys: TsgcPGPKeyRing;
out aResult: TsgcPGPDecryptResult): TBytes;
var
oSecretRing: TsgcPGPKeyRing;
oResult: TsgcPGPDecryptResult;
oData: TBytes;
begin
oSecretRing := TsgcPGPKeyRing.Create;
try
oSecretRing.LoadFromFile('bob-secret.asc');
try
oData := sgcPGP_Decrypt(oEncrypted, oSecretRing, 'bob passphrase',
oPublicRing, oResult);
WriteLn(sgcPGP_UTF8ToString(oData));
if oResult.Verify.Valid then
WriteLn('signed by ' + oResult.Verify.SignerUserID)
else if oResult.Verify.Signed then
WriteLn('signature not valid: ' + oResult.Verify.Status);
except
on E: EsgcPGPError do
WriteLn('cannot decrypt: ' + E.Message);
end;
finally
oSecretRing.Free;
end;
end;
TsgcPGPDecryptResult kaydı, nelerin şifresinin çözüldüğünü açıklar:
| Alan | Anlamı |
| FileName | Literal veri paketinde saklanan dosya adı, boş olabilir |
| Date | Literal veri tarihi, Unix zamanı |
| Format | Literal veri biçimi baytı: 'b' ikili, 't' veya 'u' metin |
| Encrypted | Girdi şifreliyse True, yalnızca imzalı bir mesaj için False |
| SymAlgo | Simetrik algoritma kimliği (AES-128, AES-192, AES-256 için 7, 8, 9) |
| AEADAlgo | AEAD modu kimliği (1 EAX, 2 OCB, 3 GCM), SEIPD v1 için 0 |
| RecipientKeyID | Mesajın şifresini çözen gizli anahtarın anahtar kimliği, bir parola için boş |
| Verify | Gömülü imza için bir TsgcPGPVerifyResult, aşağıya bakın |
İmzalama ve doğrulama
Üç tür imza olağan durumları kapsar:
İmzalayıcının kilidi açık olmalıdır. aTextMode, metni kanonik CRLF satır sonlarıyla imzalar, böylece imza dosya Windows ile Linux arasında taşındıktan sonra da doğrulanır.
function sgcPGP_Sign(const aData: TBytes; aSigner: TsgcPGPKey;
aDetached: Boolean = True; aArmor: Boolean = True; aTextMode: Boolean = False;
const aFileName: string = ''): TBytes;
function sgcPGP_ClearSign(const aText: string; aSigner: TsgcPGPKey): string;
function sgcPGP_Verify(const aSignedMessage: TBytes; aKeys: TsgcPGPKeyRing;
out aData: TBytes; out aResult: TsgcPGPVerifyResult): Boolean;
function sgcPGP_VerifyDetached(const aData, aSignature: TBytes;
aKeys: TsgcPGPKeyRing; out aResult: TsgcPGPVerifyResult): Boolean;
var
oData, oSignature, oSigned, oOut: TBytes;
oVerify: TsgcPGPVerifyResult;
vClear: string;
begin
oData := sgcPGP_UTF8('release 1.0');
{ detached }
oSignature := sgcPGP_Sign(oData, oAlice);
if sgcPGP_VerifyDetached(oData, oSignature, oPublicRing, oVerify) then
WriteLn('valid, signed by ' + oVerify.SignerUserID);
{ inline }
oSigned := sgcPGP_Sign(oData, oAlice, False);
if sgcPGP_Verify(oSigned, oPublicRing, oOut, oVerify) then
WriteLn(sgcPGP_UTF8ToString(oOut));
{ cleartext }
vClear := sgcPGP_ClearSign('Hello', oAlice);
if sgcPGP_Verify(sgcPGP_UTF8(vClear), oPublicRing, oOut, oVerify) then
WriteLn('valid cleartext signature');
end;
TsgcPGPVerifyResult kaydı, bulunan ilk geçerli imzayı veya hiçbiri geçerli değilse ilk imzayı raporlar:
| Alan | Anlamı |
| Signed | Mesaj en az bir imza taşıyorsa True |
| Valid | Bir imza, anahtar halkasındaki geçerli bir anahtarla doğrulandıysa True |
| SignerKeyID, SignerFingerprint | İmzalayan anahtarın (veya alt anahtarın) onaltılık anahtar kimliği ve parmak izi |
| SignerUserID | İmzalayanın birincil kullanıcı kimliği |
| SignatureTime | İmza oluşturma zamanı, Unix zamanı |
| HashAlgo | Hash algoritması kimliği, sgcPGP_HashName adını verir |
| Status | Geçerliyse boş, aksi halde neden: not signed, signer key not found, bad signature, signer key not valid at signature time, signature expired, malformed signature, unexpected signature type |
Anahtar halkasında bulunmayan bir anahtardan gelen imza hiçbir zaman geçerli değildir: Status signer key not found olur ve imzalayan alanları boş kalır. Yalnızca Valid değerine güvenin ve yalnızca anahtar halkasına kendiniz koyduğunuz anahtarlar için.
GnuPG ile birlikte çalışabilirlik
GnuPG ile veri alışverişi için v4 anahtarlarını kullanın. Armor'lu dosyalar her iki yönde de değişmeden geçer. GnuPG tarafında tipik komutlar:
gpg --import alice-public.asc
gpg --armor --export bob@example.com > bob-public.asc
gpg --armor --export-secret-keys bob@example.com > bob-secret.asc
gpg --decrypt message.asc
gpg --armor --sign --encrypt --recipient alice@example.com file.txt
gpg --armor --symmetric file.txt
gpg --verify file.txt.asc file.txt
gpg --verify clearsigned.asc
gpg --armor --detach-sign file.txt
gpg --clearsign note.txt
GnuPG tarafından dışa aktarılan anahtarlar, bir parola ile korunan gizli anahtarlar dahil, TsgcPGPKeyRing.LoadFromFile ile yüklenir. GnuPG 2.4 anahtarlarını LibrePGP OCB özelliği ile işaretler ve onlara paket 20 (OCB şifreli veri) veya v5 SKESK paketleriyle şifreleyebilir. Bu mesajlar okunur ve şifreleri çözülür, ancak hiçbir zaman yazılmaz: burada bir v4 anahtarı için şifrelenen veri, her GnuPG sürümünün okuduğu SEIPD v1'i kullanır. Bir akıllı karta taşınan gizli anahtarlar, bir GnuPG dışa aktarımında gizli materyali olmayan saplamalar (stub) olarak görünür; yüklenirler, ancak imzalayamaz veya şifre çözemezler.
Güvenlik notları
Sınırlamalar
API başvurusu
| Ad | Birim | Amaç |
| sgcPGP_Encrypt | sgcCrypto_PGP | Açık anahtarlara şifreleme, isteğe bağlı olarak imzalı |
| sgcPGP_EncryptSymmetric | sgcCrypto_PGP | Bir parola ile şifreleme, v4 veya v6 |
| sgcPGP_Decrypt | sgcCrypto_PGP | Şifre çözme ve gömülü imzayı doğrulama |
| sgcPGP_Sign | sgcCrypto_PGP | Ayrık veya satır içi imza |
| sgcPGP_ClearSign | sgcCrypto_PGP | Açık metin imzası |
| sgcPGP_Verify | sgcCrypto_PGP | Satır içi veya açık metin imzalı bir mesajı doğrulama |
| sgcPGP_VerifyDetached | sgcCrypto_PGP | Ayrık bir imzayı doğrulama |
| TsgcPGPDecryptResult, TsgcPGPVerifyResult | sgcCrypto_PGP | Sonuç kayıtları |
| sgcPGPMaxDecompressedSize | sgcCrypto_PGP | Açma sınırı, 0 sınırsızdır |
| sgcPGP_GenerateKey | sgcCrypto_PGP_Cert | Bir v4 veya v6 anahtarı üretme |
| TsgcPGPKey | sgcCrypto_PGP_Cert | Kullanıcı kimlikleri ve alt anahtarlarıyla bir anahtar: LoadFromBytes, SaveToBytes, SaveToArmored, Unlock, Protect |
| TsgcPGPKeyRing | sgcCrypto_PGP_Cert | Sahip olan anahtar listesi: Add, Remove, Clear, LoadFromBytes, LoadFromFile, SaveToArmored, FindByID, FindByUserID, FindKeyPacket |
| TsgcPGPKeyType | sgcCrypto_PGP_Cert | Üretim için anahtar algoritması |
| sgcPGP_Armor, sgcPGP_Dearmor, sgcPGP_IsArmored | sgcCrypto_PGP_Packets | ASCII armor kodlama ve kod çözme |
| sgcPGP_UTF8, sgcPGP_UTF8ToString | sgcCrypto_PGP_Packets | Dizeden UTF-8 baytlara ve geri |
| sgcPGPMaxArgon2EncodedM, sgcPGPMaxArgon2Passes, sgcPGPMaxArgon2Lanes | sgcCrypto_PGP_Packets | Argon2 S2K sınırları |
| CSGC_PGP_COMP_NONE, CSGC_PGP_COMP_ZIP, CSGC_PGP_COMP_ZLIB | sgcCrypto_PGP_Packets | Şifreleme için sıkıştırma |
| EsgcPGPError | sgcCrypto_PGP_Packets | Herhangi bir OpenPGP hatasında oluşturulan istisna |
function sgcPGP_Armor(const aData: TBytes; aType: TsgcPGPArmorType;
aWithChecksum: Boolean = True): string;
function sgcPGP_Dearmor(const aText: string;
out aType: TsgcPGPArmorType): TBytes;
{ TsgcPGPArmorType = (pgpaMessage, pgpaPublicKey, pgpaPrivateKey, pgpaSignature) }
Demo
Demos\18.Cryptography\09.OpenPGP klasörü (sgcOpenPGP.dpr) bu sayfadaki API'nin kullanımını gösterir: anahtar üretimi, şifreleme ve şifre çözme, imzalama ve doğrulama.