Teknik Makale

PDF Library for Delphi ile Delphi'de PDF Şifreleme ve İzin Denetimi

Bir izin bayrağı bir güvenlik mekanizması değildir. "Kopyalama yok" diyen bit, kriptografiyle aynı /Encrypt sözlüğü içinde yaşar, bu da ona sahip olmadığı bir uygulanabilirlik havası verir ve ikisini tek bir şeymiş gibi ele aldığınız an denetiminiz yanlış cevaplar üretmeye başlar. Bir PDF'e sorulmaya değer tek soru "şifrelenmiş mi" değildir. Daha spesifik ve daha zor bir sorudur: hangi algoritma, hangi güvenlik işleyici revizyonu, iki paroladan hangisi ayarlanmış, hangi izin bitleri iddia ediliyor ve şifreleme dosyanın gerçekte hangi bölümlerine dokunuyor. Bir dosya resmi olarak şifrelenmiş ve pratikte açık olabilir. Okunmayı reddedebilir ama meta verisini düz metin halinde bırakabilir. Yazdırmayı, herhangi bir görüntüleyicinin görmezden gelmekte özgür olduğu bir bayrakla kilitleyebilir. Bir PDF'i denetlemek, tüm bunları ayrı ayrı çözmek anlamına gelir ve losLab'ın Delphi ve C++Builder için PDF motoru olan PDF Library for Delphi, her birini hem düz bir tam sayı tutamaç API'si hem de tipli bir sınıf katmanı üzerinden sunar

/Encrypt sözlüğünün gerçekte kaydettikleri

ISO 32000-1 §7.6, belge güvenliğini bir avuç sözlük girdisi aracılığıyla tanımlar ve PDF Library for Delphi bunları TPDFEncryption kaydında birebir yansıtır. Filtre sürümü V ve revizyon R, algoritma ailesini seçer. Length anahtar boyutunu taşır. İzin bitleri P'de, sahip ve kullanıcı parola doğrulama dizeleri ise O ve U'da yer alır (AES-256 için OE ve UE eklenmiştir), bir EncryptMetadata bayrağı bunlara eşlik eder ve üç alan daha, sırasıyla dizelere, akışlara ve gömülü dosyalara uygulanan şifreleme filtrelerini adlandırır

Bu kaydın değeri, sizin için hiçbir şeyi yorumlamamasıdır. Ham sözlüğü geri verir ve sonuçları sizin çıkarmanıza bırakır, ki bu tam olarak bir denetimin ihtiyaç duyduğu şeydir. Şifreli içinde düz metin durumu StringFilterIdentity ve StreamFilterIdentity'de ortaya çıkar: ikisinden biri doğruysa, belgenin şifrelenmiş durumu ne bildirirse bildirsin, karşılık gelen veri Identity filtresinden dokunulmadan geçer. "Bir /Encrypt sözlüğü var" noktasında duran bir tarayıcı, dizeleri ve akışları açık halde otururken böyle bir dosyayı korunmuş olarak adlandıracaktır. Aynı ince ayrım meta veri için de geçerlidir. EncryptMetadata false olduğunda XMP paketi herhangi bir indeksleyici için okunabilir kalırken sayfa içeriği kalmaz, bu da yönlendirme kurallarınızın bir başlık veya yazar alanına dayandığı anda bilinmeye değer bir şeydir

PDF Library for Delphi şeması: PDF /Encrypt sözlüğü alanlarının, Identity şifreleme filtresi tuzakları da dahil TPDFEncryption denetim özelliklerine eşlenmesi
Her /Encrypt girdisi bir TPDFEncryption alanına eşlenir; Identity filtresi bayrakları ise hangi dizgelerin, akışların veya meta verilerin şifreleme durumundan bağımsız olarak okunabilir kaldığını gösterir

Düz API ile kısa bir güvenlik incelemesi

Çoğu iş akışı için dört düz çağrı, gündelik soruları yanıtlar. LoadFromFile başarı durumunda 1 döndürür ve belge açıldıktan sonra şifreleme denetleyicileri onun çözülmüş durumuna göre rapor verir:

var
  PDF: TPDFlib;
begin
  PDF := TPDFlib.Create;
  try
    if PDF.LoadFromFile('contract.pdf', UserPassword) <> 1 then
      raise Exception.Create('Open failed: wrong password or damaged file');
    Writeln('status    : ', PDF.EncryptionStatus);     // çözülmüş / şifreli / bilinmiyor
    Writeln('algorithm : ', PDF.EncryptionAlgorithm);  // RC4'e karşı AES ailesi
    Writeln('strength  : ', PDF.EncryptionStrength);   // anahtar uzunluğu sınıfı
    Writeln('owner pw? : ', PDF.CheckPassword(CandidatePassword));
  finally
    PDF.Free;
  end;
end;

CheckPassword, tek satırlık imzasının ima ettiğinden daha fazla önem taşır. PDF, eşit olmayan güce sahip iki parola tanımlar. Dosyayı hiç açabilmek için kullanıcı parolası gereklidir. Sahip parolası tam haklar verir ve her izin bitini geçersiz kılar. Diskteki baytlar her iki durumda da aynıdır, ancak sahip parolası altında açılan bir oturum, kullanıcı parolası oturumunun yapamayacağı şeyleri yapabilir, bu yüzden hangi kimlik bilgisinin sunulduğunu kaydetmeyen bir denetim, gerçeğin yalnızca yarısını kaydediyordur. Sınıf katmanı bu ayrımı sorgulanabilir hale getirir. TPDFDocument.HasUserPassword ve HasOwnerPassword, dosyanın neyi gerektirdiğini bildirirken, IsUserPassword ve IsOwnerPassword, geçerli oturumu gerçekte hangi parolanın açtığını bildirir. Bu gerçeği günlüğe kaydedin. Parola değerlerinin kendilerini asla günlüğe kaydetmeyin

Strength merdiveni: "AES-256" iki şey anlamına geldiğinde

Düz Encrypt ve EncryptFile fonksiyonları, beş anlamlı değere sahip bir tam sayı Strength alır: 40 bit RC4 için 0, 128 bit RC4 için 1, Acrobat 7'den itibaren okunabilir 128 bit AES için 2, Acrobat 9 ile tanıtılan 256 bit AES için 3 ve Acrobat X ve sonrasının gerektirdiği 256 bit AES için 4

İlginç kısım, 3 ve 4'ün her ikisinin de AES-256 olarak etiketlenmiş olması ama aynı şema olmamalarıdır. Strength 3, Acrobat 9'un gönderdiği ve ISO'nun hiç benimsemediği geçici bir tasarım olan güvenlik işleyici revizyon 5'e eşlenir. Strength 4 ise, anahtar türetme fonksiyonu güçlendirilip ISO 32000-2'de standartlaştırılan revizyon 6'ya eşlenir. Bugün oluşturduğunuz bir belge için 4 yerine 3'ü seçmek için hiçbir neden yoktur. Bir denetim için ise bu fark belirleyicidir: "ISO 32000-2'ye göre AES-256" diye okunan bir politika yalnızca R6 tarafından karşılanır ve kendini AES-256 olarak adlandıran bir R5 dosyası, saf bir strength kontrolünü geçerken bu politikayı başaramaz. Sınıf katmanı ikisini isimle ayrı tutar, R5 için esAES256Bit ile R6 için esAES256BitAcroX, ve EncryptionAcroX özelliği revizyon sorusunu tek bir boole ile yanıtlar

Delphi denetimleri için 40 bit RC4'ten AES-256 revizyon 5 ve revizyon 6'ya uzanan PDF şifreleme Güç merdiveni
3 ve 4 güç düzeylerinin ikisi de AES-256 diye anılır; ama yalnızca revizyon 6 bir ISO 32000-2 politikasını karşılar, bu yüzden denetimler etiketi değil işleyici revizyonunu kaydetmelidir

İzin bitleri ve anahtar uzunluğuna ilişkin ince baskı hükümleri

EncodePermissions, Encrypt ve EncryptFile'ın beklediği tam sayıya sekiz bayrağı paketler. Yazdır, kopyala, değiştir ve not ekle temel kümeyi oluşturur; alanları doldur, erişilebilirlik için kopyala, birleştir ve tam kaliteli yazdırma ise genişletilmiş kümeyi oluşturur. Kütüphanenin kendi şifreleme demosunun açıkça belirttiği ince baskı hükmü, genişletilmiş dördün yalnızca 128 bit ve üzeri güçte etkili olmasıdır. Tam kaliteli yazdırma bayrağı da aynı kurala tabidir: düşük çözünürlüklü yazdırmayı zorlamak için onu temizleyin, 40 bit bir belge sizi görmezden gelecektir, çünkü bu düşürme de 128 bit veya daha güçlü şifreleme gerektirir. "Yalnızca düşük çözünürlüklü yazdırma" politikasını 40 bit bir dosyaya kodlayın, her görüntüleyici yine de tam kalitede yazdıracaktır

Daha derin soru bu bitleri kimin uyguladığıdır ve cevap, güvenebileceğiniz hiç kimsenin uygulamadığıdır. İzinler, kriptografik kısıtlamalar değil, uyumlu okuyuculara yönelik talimatlardır. Şifre çözme anahtarı, kopyalamaya izin verilsin ya da verilmesin aynıdır, bu yüzden kilitlenmiş bir izin kümesi yalnızca dürüst görüntüleyicileri dürüst tutar. Bitleri görmezden gelmeyi seçen bir okuyucu hiçbir kriptografik engelle karşılaşmaz. Yükümlülük çıkarmayı caydırmak değil engellemekse, dosyanın bir kullanıcı parolasına ve iş akışının bunun etrafında süreç düzeyinde kontrollere ihtiyacı vardır ve bir denetim raporu, bir izin bayrağını kilit gibi ele almak yerine her dosyanın gerçekte bu iki rejimden hangisi altında olduğunu belirtmelidir

Politikayı ayarlamak ve uygulandığını kanıtlamak

Mevcut dosyalara şifreleme uygulamak, onları nesne ağacına yüklemeyi gerektirmez. EncryptFile, girdiden çıktıya tek bir çağrıda işler ve denetim döngüsü, diske ne indiğini doğrulamak için sonucu yeniden açar. Ürünle birlikte gelen şifreleme demosu, aynı yaz-sonra-geri-oku şeklini izler:

var
  PDF: TPDFlib;
  R: Integer;
begin
  PDF := TPDFlib.Create;
  try
    R := PDF.EncryptFile('in.pdf', 'out.pdf', 'owner-secret', 'user-secret', 4,
      PDF.EncodePermissions(1, 0, 0, 0,    // yazdırmaya izin verilir; kopyalama/değiştirme/notlar reddedilir
                            0, 0, 0, 1));  // genişletilmiş küme: yalnızca tam kaliteli yazdırma
    if (R = 1) and (PDF.LoadFromFile('out.pdf', 'user-secret') = 1) then
    begin
      Writeln('algorithm = ', PDF.EncryptionAlgorithm);
      Writeln('strength  = ', PDF.EncryptionStrength);
      Writeln('owner pw accepted: ', PDF.CheckPassword('owner-secret'));
    end;
  finally
    PDF.Free;
  end;
end;

Belge katmanında çalışan ekipler, bit paketleme yerine tipli kümelerle aynı işlemi elde eder, ki bu kod incelemesinden çok daha az göz kırpmayla geçer:

if not Doc.Encrypt('owner-secret', 'user-secret', esAES256BitAcroX,
  [ppCanPrint], [ppCanPrintFull]) then
  raise Exception.Create('Encryption failed');

Her iki durumda da geri okuma adımı isteğe bağlı bir tören değildir. Aksi halde aylar sonra bir müşterinin makinesinde ortaya çıkacak dağıtım hatalarını yakalar: istenen strength'i sessizce düşüren eski bir kütüphane derlemesi, dizin salt okunur olduğu için hiç yazılmamış bir çıktı yolu, argümanları yanlış sırada giden bir izinler tam sayısı. Üçü de yerel bir duman testini geçer ve sahada başarısız olur, çıktıyı yeniden açmak ise her birini, dosyayı oluşturan çalıştırma sırasında gördüğünüz bir istisnaya dönüştürür. GetEncryptionFingerprint, iş kaydıyla birlikte saklayabileceğiniz kompakt bir değer döndürür, böylece daha sonraki bir karşılaştırma, ikisini de yeniden açmadan iki çıktının aynı şifreleme yapılandırmasını paylaşıp paylaşmadığını söyleyebilir

Kodlanmaya değer denetim yanlış pozitifleri

Birkaç kalıp, güvenilir biçimde güvenlik tarayıcılarını yanlış sonuca iter ve her biri çok parçalı bir soruyu evet-hayır cevabına indirgemekten kaynaklanır. Identity şifreleme filtresi en temiz örnektir. Bir /Encrypt sözlüğü mevcuttur, dosya şifreli olarak bildirilir ve yine de dizeler ve akışlar Identity filtresinden değişmeden geçer, bu yüzden gerçek içerik düz metindir. Herhangi bir şeyi korunmuş ilan etmeden önce StringFilterIdentity ve StreamFilterIdentity'yi okumak çözümdür

Meta veri ayrımı daha inceliklidir. EncryptMetadata, belgenin geri kalanıyla her iki yönde de çelişebilir, şifreli bir dosyayı okunabilir bir XMP paketiyle bırakabilir ya da daha az sıklıkla tam tersini yapabilir. "Dosya şifreli" ifadesi, meta verisinin şifreli olup olmadığı hakkında hiçbir şey söylemez, bu da bir indeksleyici ya da yönlendirme kuralı başlığa uzandığı anda önem kazanır. Gömülü dosyalar üçüncü bir eksen ekler: PDF, yalnızca ekler için özel bir şifreleme filtresine izin verir, bu yüzden ekler, aksi halde açık olan bir belgenin tek şifreli parçası ya da şifreli bir belgenin tek düz metin parçası olabilir. Üç filtre atamasını dizeler, akışlar ve gömülü dosyalar için ayrı alanlar olarak yakalayın, bu tuzakların hiçbiri sizi yakalayamaz. Tek bir boole saklayın, yanlış çağrı yalnızca an meselesidir

PDF Library for Delphi: Bir PDF'yi korumalı diye nitelendirmeden önce StringFilterIdentity, StreamFilterIdentity, EncryptMetadata ve gömülü dosya şifreleme filtresini kontrol eden denetim akışı
Dört bağımsız eksen, şifreli görünen bir dosyanın gerçekten mühürlü olup olmadığına karar verir; bunları tek bir boolean'da birleştirmek er ya da geç bir dosyayı yanlış sınıflandırır

Şifrelemeyi kaldırmak ve yeni dosyalar için seçmek

Bir denetim genellikle korumayı kaldırma kararıyla sona erer ve buradaki engel mekanikler değildir. DecryptFile(InputFileName, OutputFileName, Password), tam yükleme olmadan şifresi çözülmüş bir kopya yazar ve bir dosya zaten açıldığında yüklenmiş belgenin Decrypt'i aynı işi bellekte yapar. İkisi de geçerli bir parola gerektirir; hiçbiri kriptografiyi atlamaz. Gerçek kapı kod değil politikadır, bu yüzden alım kurallarınız kaldırmaya ne zaman izin verildiğini açıkça belirtsin ve buna yetki veren parola sınıfını kaydetsin, çünkü teknik adımın kendisi hiçbir iz bırakmaz

Yeni çıktı için seçim, beş Strength değerinin ima ettiğinden daha dardır. Dosyaları Acrobat X'ten daha eski görüntüleyicilerde açmanız gerekmedikçe Strength 4, AES-256 revizyon 6 kullanın. Strength 2, AES-128, yükseltilemeyen yaşlı bir görüntüleyici filosu için pragmatik tabandır. 0 ve 1'deki RC4 seçenekleri, tarihsel arşivleri okuyup denetleyebilmeniz içindir, onlarla yeni bir şey üretebilmeniz için değil; 2026 tasarımında onlara yönelmek, yukarı akıştaki bir gereksinimin bayatladığının işaretidir

Şifreleme durumu doğrudan imzalama kararlarını besler, çünkü belgeleri doğrulayan ve imzalayan bir çalışma tezgahı, bu denetimin dayandığı aynı geri okuma disiplinine ihtiyaç duyar. Bu zemin uyumluluk ve imzalama çalışma tezgahı makalesinde ele alınır. Bir toplu işlem, EncryptFile'ı binlerce büyük belge genelinde uyguladığında, büyük PDF'ler için doğrudan erişim rehberi, çalışırken belleği nasıl düz tutacağınızı gösterir. Eksiksiz şifreleme API referansı PDF Library for Delphi ürün sayfasında bulunur