687326 Enhancement: Handling of PDF 1.5 encryption. (XEFITRA)
"Dan Coby" <[email protected]>
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <[email protected]> |
The PDF 1.5 specification has added several some features for
encryption of PDF documents.
1. The new encryption changes are indicated by a /R value of
4 in the Encryption dictionary. Note: The encryption algorithm
is the same as /R = 3.
2. The encryption handling for strings and streams may now be
specified independently. Current possibilities are 'Identity'
and the standard handler.
Below is the code for implementing these changes.
Dan
Index: lib/pdf_sec.ps
===================================================================
RCS file: /cvs/ghostscript/gs/lib/pdf_sec.ps,v
retrieving revision 1.13
diff -u -r1.13 pdf_sec.ps
--- a/lib/pdf_sec.ps 16 Jan 2004 02:02:58 -0000 1.13
+++ b/lib/pdf_sec.ps 27 Feb 2004 06:58:27 -0000
@@ -111,8 +111,8 @@
} ifelse
3 { concatstrings } repeat md5_trunk
- % Step 6.
- Trailer /Encrypt oget /R oget 3 eq {
+ % Step 6. Only executed for /R equal to 3 or more
+ Trailer /Encrypt oget /R oget 3 ge {
50 { md5_trunk } repeat
} if
@@ -162,9 +162,13 @@
dup 3 eq {
pop pdf_gen_user_password_R3
} {
- ( **** This file uses an unknown standard security handler
revision: )
- exch =string cvs concatstrings pdfformaterror printProducer
- /pdf_check_user_password cvx /undefined signalerror
+ dup 4 eq { % 4 uses the algorithm as 3
+ pop pdf_gen_user_password_R3
+ } {
+ ( **** This file uses an unknown standard security handler
revision: )
+ exch =string cvs concatstrings pdfformaterror printProducer
+ /pdf_check_user_password cvx /undefined signalerror
+ } ifelse
} ifelse
} ifelse
} bind def
@@ -192,8 +196,8 @@
% Step 2.
md5_trunk
- % 3.3 Step 3.
- Trailer /Encrypt oget /R oget 3 eq {
+ % 3.3 Step 3. Only executed for /R equal to 3 or more
+ Trailer /Encrypt oget /R oget 3 ge {
50 { md5_trunk } repeat
} if
@@ -210,8 +214,8 @@
Trailer /Encrypt oget dup /O oget 2 index arc4decode
% <encryption-key> <encrypt-dict> <decrypted-O>
- % Step 3.
- exch /R oget 3 eq {
+ % Step 3. Only executed for /R equal to 3 or more
+ exch /R oget 3 ge {
1 1 19 {
2 index pdf_xorbytes arc4decode
} for
@@ -316,10 +320,28 @@
}
{ exch pop PDFDEBUG { dup ==only ( ) print flush } if
dup type /stringtype eq
- { 1 index arc4decode
- PDFDEBUG { (%Decrypted: ) print dup == flush } if
+ {
+ % Check if we have encrypted strings R=4 allows for
+ % selection of encryption on streams and strings
+ Trailer /Encrypt oget % Get encryption dictionary
+ dup /R oget 4 lt % only 4 has selectable
+ { % R < 4 --> encrypted strings
+ pop 1 index arc4decode % Decrypt string
+ PDFDEBUG { (%Decrypted: ) print dup == flush } if
+ } { % Else R = 4
+ /StrF knownoget % Get StrF (if present)
+ { % If StrF is present ...
+ /Identity eq not % Check if StrF != Identity
+ { 1 index arc4decode % Decrypt string
+ PDFDEBUG { (%Decrypted: ) print dup == flush } if
+ }
+ if % If StrF != identity
+ }
+ if % If StrF is known
+ }
+ ifelse % Ifelse R < 4
}
- if
+ if % If = stringtype
exch pop
}
ifelse
@@ -334,26 +356,45 @@
% Run the code to resolve an object reference.
/pdf_run_resolve
- { /FileKey where
- { pop
- 2 copy computeobjkey dup 4 1 roll
- PDFfile exch resolveopdict .decpdfrun
- dup dup dup 5 2 roll
+{ /FileKey where % Check if the file is encrypted
+ { pop % File is encrypted
+ 2 copy computeobjkey dup 4 1 roll
+ PDFfile exch resolveopdict .decpdfrun
+ dup dup dup 5 2 roll
% stack: object object key object object
- xcheck exch type /dicttype eq and
- { /StreamKey exch put }
- { pop pop }
- ifelse
- }
- { PDFfile resolveopdict .pdfrun }
- ifelse
- } bind def
+ xcheck exch type /dicttype eq and % Check if possible stream
+ { % Check if we have encrypted streams. R=4 allows for
+ % selection of encryption on streams and strings
+ Trailer /Encrypt oget % Get encryption dictionary
+ dup /R oget 4 lt % only 4 has selectable
+ { % R < 4 --> encrypted
streams
+ pop /StreamKey exch put % Insert StreamKey in
dictionary
+ } { % Else R = 4
+ % Check for StmF = Identity
+ /StmF knownoget % Get StmF (if present)
+ { % If StmF is present ...
+ /Identity eq % Check if StmF = Identity
+ { pop pop % Identity --> no encryption
+ } { % Else we have an encrption handler
+ /StreamKey exch put % Insert StreamKey into dictionary
+ } ifelse % Ifelse StmF = identity
+ } { % Else StmF not present, default =
Identity
+ pop pop % Identity --> no encryption
+ } ifelse % Ifelse StmF is known
+ } ifelse % Ifelse R < 4
+ } { % Else object is not a
dictionary
+ pop pop % ignore object
+ } ifelse % Ifelse possible stream
+ } { % Else file is not encrypted
+ PDFfile resolveopdict .pdfrun
+ } ifelse % Ifelse encrypted
+} bind def
% Prefix a decryption filter to a stream if needed.
% Stack: readdata? dict parms file/string filternames
% (both before and after).
/pdf_decrypt_stream
- { 3 index /StreamKey known
+ { 3 index /StreamKey known % Check if the file is encrypted
{
exch
% Stack: readdata? dict parms filternames file/string