Zaten AES-256 şifrelemesi taşıyan bir fatura PDF'ini alın ve Delphi ve C++Builder için PDFium Bileşeni'nden (PDFiumPas) onu arşivleme için PDF/A olarak damgalamasını veya PAdES ile imzalamasını, tam bir yeniden yazım yerine artımlı bir güncelleme aracılığıyla isteyin. Kütüphane, şifreli baytları doğrudan yamalayarak oraya varmayacaktır: altı uyumluluk işaretçisi enjektörü mevcut bir /Encrypt girdisini tespit eder ve kaynağı bayt bayt değişmeden geçirir ve PAdES imzalayıcısı, hiçbir doğrulayıcının kabul etmeyeceği bir imza yaymak yerine tamamen bir istisna fırlatır
Bu, oluşturmadığınız bir PDF'i gizli risk için denetlemekten farklı bir sorudur; bu kendi başına salt okunur bir egzersizdir. Bu makale aynı güven sınırının yazma tarafı hakkındadır: baytları zaten başka birinin şifresinin arkasında kilitli bir dosyaya, o kod sonradan ona bir şey eklemeye çalıştığı anda, kendi kodunuzun yapmasına izin verilen şey nedir
Şifreli bir PDF'i güncellediğinizde ISO 32000-1 ne gerektirir?
ISO 32000-1 §7.5.6, bir artımlı güncellemenin arka planının, /Prev hariç önceki arka plandaki her girdiyi tekrarlamasını gerektirir ve Tablo 15, /Encrypt'i bir arka planın taşıyabileceği girdiler arasında listeler. Onu yeni arka plandan düşürün ve uyumlu bir okuyucunun eksiklikten şüphelenmesi için hiçbir nedeni yoktur: en yeni arka plan yetkilidir; bu yüzden orada /Encrypt bulamayan bir okuyucu, tüm dosyanın şifresiz olduğuna karar verir ve daha eski, hâlâ şifrelenmiş gövdeyi düz baytlar olarak ayrıştırmaya çalışır. /Encrypt'i yeni arka planda tutun ama güncellemenin kendi nesnelerini düz metin olarak yazın ve başarısızlık yalnızca bir adım sonraya kayar: okuyucu şifrelemeyi doğru şekilde tespit eder, dokunduğu her nesneyi -başlangıçta hiç şifrelenmemiş yeni olanlar dahil- dosyanın şifresinden geçirir ve şifre çözme ona dokunmadan önce mükemmel şekilde okunaklı olan içerik için geri gürültü alır. Her iki hata da bayt düzeyinde normal, iyi biçimlendirilmiş bir artımlı güncelleme gibi görünen bir dosya üretir, tam olarak uyumlu bir okuyucu onu açana kadar
Altı işaretçi enjektörü, bir v2.14.2 şifreleme kapısı
PDFiumPas, etiketleyebildiği her ISO PDF alt kümesi için bir tane olmak üzere altı bayt düzeyinde işaretçi enjektörü gönderir: PDF/A (ISO 19005), PDF/X (ISO 15930), PDF/UA (ISO 14289-1), PDF/E-1 (ISO 24517-1), PDF/R-1 (ISO 23504-1) ve PDF/VT-1 (ISO 16612-2). Her biri, PDFium'un kendi FPDF_SaveAsCopy'sinin zaten yazdığı baytları alır ve bunların üzerine ikinci, daha küçük bir artımlı güncelleme katmanlar: yeni bir XMP meta veri akışı, ona işaret eden bir katalog sözlüğü düzenlemesi ve baskı odaklı alt kümeler için bir OutputIntent ve ICC profili. v2.14.2 itibarıyla, InjectPdfAMarkers, InjectPdfXMarkers, InjectPdfUaMarkers, InjectPdfEMarkers, InjectPdfRMarkers ve InjectPdfVTMarkers'ın her biri önce kaynak arka planı okur ve mevcut bir /Encrypt girdisi bildirirse, kaynağı hedef akışa değişmeden kopyalar ve hemen döner. XMP yok, OutputIntent yok, katalog düzenlemesi yok -çağıran orijinal dosyayı bayt bayt geri alır
var
Src, Dst: TFileStream;
Opts: TPdfXSaveOptions;
begin
Src := TFileStream.Create('signed-encrypted-proof.pdf', fmOpenRead);
Dst := TFileStream.Create('pdfx-attempt.pdf', fmCreate);
try
Opts.Conformance := pxc4;
InjectPdfXMarkers(Src, Dst, Opts);
// pdfx-attempt.pdf is byte-identical to the source: still encrypted,
// no /GTS_PDFXVersion, no OutputIntent. Nothing was written, and
// nothing was corrupted either
finally
Dst.Free;
Src.Free;
end;
end;
Şifrelenmesine izin verilmesi, içine enjekte etmenin güvenli olmasıyla aynı şey değildir
PDF/E-1 ve PDF/R-1'in ikisi de, ana belgelerinin spesifikasyon düzeyinde şifrelenmesine açıkça izin verir; bu, gerçekte diskte ne olması gerektiğine bakana kadar bir muafiyet gibi okunur. ISO 24517-1 §6.3, PDF/E-1 için şifrelemeye izin verir ve ISO 23504-1 §6.2.3, başlık %PDF-2.0 bildirdiği sürece PDF/R-1 için buna izin verir. Hiçbir madde, bayt düzeyinde bir son işlemcinin o şifreli kapsayıcıya güvenle düz metin bir nesne ekleyip ekleyemeyeceği hakkında bir şey söylemez ve ekleyemez, diğer her alt kümeye uygulanan aynı §7.5.6 nedenleriyle. PDFiumPas'ın bu iki profil için kendi uyumluluk doğrulayıcıları, ValidatePdfECompliance ve ValidatePdfRCompliance, /Encrypt'in varlığını kasıtlı olarak bir kusur olarak işaretlemeden kaydeder ki bu, hiçbir zaman bir bayt yazmayan salt okunur bir doğrulayıcı için doğrudur. Bu aynı zamanda üzerinden hızlıca geçip kardeş enjektörün ayrı bir korumaya ihtiyacı olmadığını varsaymanın kolay olduğu bir örüntüdür de, oysa enjektör çiftteki gerçekten reddetmesi gereken tek fonksiyondur
SaveAsPdfX belgenizin şifresini sessizce çözer mi?
Evet, bir enjektörü doğrudan çağırmak yerine kamuya açık kolaylık metotlarından geçtiğiniz her seferinde. TPdf.SaveAsPdfA, SaveAsPdfX, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfR ve SaveAsPdfVT'nin her biri, bu baytları eşleşen enjektörüne vermeden önce mevcut belgeyi SaveAs(Tmp, saRemoveSecurity) ile geçici bir akışa render eder. saRemoveSecurity, PDFium'un kendi FPDF_REMOVE_SECURITY bayrağına eşlenir; bu yüzden enjektörün aldığı geçici kopya en başından hiç şifrelenmemiştir ve enjektörün /Encrypt koruması tetiklenmesi için hiçbir neden bulamaz. Çıktı, PDF/A, PDF/X, PDF/UA, PDF/E-1, PDF/R-1 veya PDF/VT-1 işaretçilerinizi taşır, ama artık kaynağı açan her ne şifreyle korunuyorsa onunla korunmuyordur
Bu ödünleşim, aşağı akışta biri "korumalı" arşiv kopyasını şifre olmadan açıp yalnızca işe yaradığını fark edene kadar görünmez. Düzeltme farklı bir metot çağrısı değildir; PDFiumPas'ın saRemoveSecurity ile eşleşecek bir saAddSecurity karşılığı yoktur, çünkü altta yatan PDFium motoru hiçbir zaman yeni şifreleme yazmak için değil, yalnızca onu kaldırmak için kuruldu. Her iki özellik de tek bir dosya için önemliyse, şifreleme, aynı SaveAsPdfA çağrısına katlanmış değil, uyumluluk işaretçilerinden sonra uygulanan, sahip olduğunuz ayrı bir adım olmak zorundadır
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.Password := 'open-secret'; // needed to open the source at all
Pdf.FileName := 'signed-encrypted-invoice.pdf';
Pdf.LoadDocument;
Pdf.SaveAsPdfA('invoice-pdfa.pdf', pac2b);
// invoice-pdfa.pdf now declares PDF/A-2b, but SaveAs(saRemoveSecurity)
// ran first inside SaveAsPdfA: the output opens without a password
finally
Pdf.Free;
end;
end;
Şifreli bir PDF'i PAdES ile imzaladığınızda ne olur?
PDFiumPas, bir işaretçi enjektörünün yaptığı gibi isteği sessizce düşürmek yerine tamamen reddeder. TPdf.SignPades ve SignPadesToStream'in ikisi de dahili bir SignPadesBytes'tan geçer ve kaynak arka planı ayrıştırdıktan sonra yaptığı ilk şey /Encrypt'i kontrol etmektir. Girdi mevcutsa, daha ileri gitmek yerine "SignPadesBytes: the source document is encrypted; remove encryption before signing" mesajıyla EPadesCrypto'yu fırlatır. Uzun vadeli doğrulama için sertifikaları, OCSP yanıtlarını ve CRL'leri gömülü hale getiren fonksiyon olan InjectPadesDssMarkers, aynı nedenle özdeş kontrolü, kendi mesajıyla uygular: "InjectPadesDssMarkers: the source document is encrypted; remove encryption before embedding DSS validation material"
Buradaki gerekçe, işaretçi enjektörlerinin geçişinden daha katıdır ve bu kasıtlıdır. Sessiz bir geçiş, bir PDF/A damgası için güvenlidir çünkü onu atlamak sizi başladığınız aynı geçerli PDF ile, yalnızca etiketlenmemiş olarak bırakır. İmzalama bu kadar sessizce başarısız olamaz: sessizce hiç eklenmemiş bir imza, yalnızca bir boolean sonucu kontrol eden herhangi bir çağıran koda, başarıyla eklenmiş bir imza gibi tam olarak aynı görünür. EPadesCrypto, sıradan Exception sınıfından türetilir; bu yüzden onu yakalamak öğrenmeniz gereken özel bir kontrol akışı kuralı değil, normal istisna işlemedir
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.Password := 'open-secret';
Pdf.FileName := 'encrypted-contract.pdf';
Pdf.LoadDocument;
try
Pdf.SignPades('encrypted-contract-signed.pdf', 'A1B2C3D4E5F6...');
except
on E: EPadesCrypto do
// E.Message: 'SignPadesBytes: the source document is encrypted;
// remove encryption before signing'
raise Exception.Create('Decrypt the contract before signing: '+ E.Message);
end;
finally
Pdf.Free;
end;
end;
Uyumluluk damgalarını, imzaları ve şifrelemeyi sıralamak
Pratik düzeltme sıralamadır, farklı bir kütüphane değil. Önce PDF/A, PDF/X, PDF/UA, PDF/E-1, PDF/R-1 veya PDF/VT-1 işaretçilerini uygulayın, ardından herhangi bir PAdES imzası ekleyin ve yalnızca o zaman, boru hattınızda şifrelemeyi gerçekten sahiplenen adımı çalıştırın -bu ister özel bir PDF yazıcısı, ister bir imzalama cihazı, ister kendi AES uygulamanız olsun. PDFiumPas'ın artımlı güncelleme katmanı, bu sıralamanın ortasına doğal olarak oturur, aksi takdirde bitmiş bir dosyaya küçük, hedefli nesneler ekler ve şifreleme sona ait olur, tam olarak çünkü bu, zincirdeki PDFiumPas'ın kendisinin gerçekleştiremediği veya geri alamadığı tek işlemdir
Bunların hiçbiri, PDFiumPas'ın her artımlı güncellemenin dayandığı arka plan ve çapraz referans verisini nasıl okuduğunu değiştirmez; bu, xref akışları resme girdiğinde kendi başına bir incelik kaynağıdır; bir PDF'in nesne ve xref akışlarını doğrulama makalesi, aynı arka plan okuma yolunun PDF 1.5+ sıkıştırılmış yapılarını nasıl ele aldığını ele alır. Ve bir belge bir uyumluluk damgasından daha güçlü bir şey için hazır olduğunda, Delphi'de bir PAdES B-B imzasıyla bir PDF'i imzalama makalesi, SignPades'in bu makalenin bıraktığı tam noktadan devraldığı yerdir
Burada açıklanan işaretçi enjektörleri ve SignPades metotları, PDFium'un yerel olarak sağladığı render ve salt okunur inceleme yanında, Delphi ve C++Builder için PDFium Bileşeni'nin bir parçası olarak gönderilir