OpenPGP

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
pgpkEd25519EdDSA Ed25519 + ECDH Curve25519Ed25519 + X25519
pgpkEd448kullanılamazEd448 + X448
pgpkRSA2048RSA 2048kullanılamaz (RFC 9580 asgari değeri 3072'dir)
pgpkRSA3072RSA 3072RSA 3072
pgpkRSA4096RSA 4096RSA 4096
pgpkNISTP256ECDSA + ECDH P-256ECDSA + ECDH P-256
pgpkNISTP384ECDSA + ECDH P-384ECDSA + ECDH P-384
pgpkNISTP521ECDSA + ECDH P-521ECDSA + 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ı
FileNameLiteral veri paketinde saklanan dosya adı, boş olabilir
DateLiteral veri tarihi, Unix zamanı
FormatLiteral veri biçimi baytı: 'b' ikili, 't' veya 'u' metin
EncryptedGirdi şifreliyse True, yalnızca imzalı bir mesaj için False
SymAlgoSimetrik algoritma kimliği (AES-128, AES-192, AES-256 için 7, 8, 9)
AEADAlgoAEAD modu kimliği (1 EAX, 2 OCB, 3 GCM), SEIPD v1 için 0
RecipientKeyIDMesajın şifresini çözen gizli anahtarın anahtar kimliği, bir parola için boş
VerifyGö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ı
SignedMesaj en az bir imza taşıyorsa True
ValidBir 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ı
HashAlgoHash algoritması kimliği, sgcPGP_HashName adını verir
StatusGeç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_EncryptsgcCrypto_PGPAçık anahtarlara şifreleme, isteğe bağlı olarak imzalı
sgcPGP_EncryptSymmetricsgcCrypto_PGPBir parola ile şifreleme, v4 veya v6
sgcPGP_DecryptsgcCrypto_PGPŞifre çözme ve gömülü imzayı doğrulama
sgcPGP_SignsgcCrypto_PGPAyrık veya satır içi imza
sgcPGP_ClearSignsgcCrypto_PGPAçık metin imzası
sgcPGP_VerifysgcCrypto_PGPSatır içi veya açık metin imzalı bir mesajı doğrulama
sgcPGP_VerifyDetachedsgcCrypto_PGPAyrık bir imzayı doğrulama
TsgcPGPDecryptResult, TsgcPGPVerifyResultsgcCrypto_PGPSonuç kayıtları
sgcPGPMaxDecompressedSizesgcCrypto_PGPAçma sınırı, 0 sınırsızdır
sgcPGP_GenerateKeysgcCrypto_PGP_CertBir v4 veya v6 anahtarı üretme
TsgcPGPKeysgcCrypto_PGP_CertKullanıcı kimlikleri ve alt anahtarlarıyla bir anahtar: LoadFromBytes, SaveToBytes, SaveToArmored, Unlock, Protect
TsgcPGPKeyRingsgcCrypto_PGP_CertSahip olan anahtar listesi: Add, Remove, Clear, LoadFromBytes, LoadFromFile, SaveToArmored, FindByID, FindByUserID, FindKeyPacket
TsgcPGPKeyTypesgcCrypto_PGP_CertÜretim için anahtar algoritması
sgcPGP_Armor, sgcPGP_Dearmor, sgcPGP_IsArmoredsgcCrypto_PGP_PacketsASCII armor kodlama ve kod çözme
sgcPGP_UTF8, sgcPGP_UTF8ToStringsgcCrypto_PGP_PacketsDizeden UTF-8 baytlara ve geri
sgcPGPMaxArgon2EncodedM, sgcPGPMaxArgon2Passes, sgcPGPMaxArgon2LanessgcCrypto_PGP_PacketsArgon2 S2K sınırları
CSGC_PGP_COMP_NONE, CSGC_PGP_COMP_ZIP, CSGC_PGP_COMP_ZLIBsgcCrypto_PGP_PacketsŞifreleme için sıkıştırma
EsgcPGPErrorsgcCrypto_PGP_PacketsHerhangi 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.