687347 Implementation of the PDF 1.5 encryption feature: EncryptMetadata

"Dan Coby" <[email protected]>
Newsgroups gmane.comp.printing.ghostscript.patches
Message-ID <[email protected]>

Implement 687347: Implementation of the PDF 1.5 encryption feature:
EncryptMetadata.  Past versions of the PDF encryption have always
encrypted metadata.  With PDF 1.5, it is possible to NOT encrypt
metadata streams.  I.e. By adding '/EncryptMetadata false' to the
encryption dictionary.

DETAILS:

There are two pieces to the implementation:

1.  The calculation of the user password key includes an additional
step of feeding 0xffffffff to the md5 input if EncryptMetadata is
false.  (Ask Adobe, not me.)

2.  Streams need to be check to see if the type is Metadata.  If so
then value for EncryptMetadata needs to be checked.  If false then
the stream does not need to be decrypted.


Dan


Index: lib/pdf_sec.ps
===================================================================
RCS file: /cvs/ghostscript/gs/lib/pdf_sec.ps,v
retrieving revision 1.14
diff -u -r1.14 pdf_sec.ps
--- a/lib/pdf_sec.ps    4 Mar 2004 05:06:38 -0000       1.14
+++ b/lib/pdf_sec.ps    6 Mar 2004 07:18:00 -0000
@@ -54,7 +54,7 @@
 } bind def

 /md5_trunk {
-  md5 pdf_key_length 0 exch getinterval
+  md5 0 pdf_key_length getinterval
 } bind def


@@ -109,12 +109,30 @@
     ()
     (   **** ID key in the trailer is required for encrypted files.\n)
pdfformaterror
   } ifelse
-  3 { concatstrings } repeat md5_trunk
+  3 { concatstrings } repeat

-  % Step 6.  Only executed for /R equal to 3 or more
-  Trailer /Encrypt oget /R oget 3 ge {
+  % The following only executed for /R equal to 3 or more
+  Trailer /Encrypt oget dup /R oget dup 3 ge {
+
+     % The following only executed for /R equal to 4
+     % Step 6.  If EncryptMetadata is false, pass 0xFFFFFFFF to md5
function
+     4 eq {
+       /EncryptMetadata knownoget      % Get EncryptMetadata (if present)
+       not { true } if                 % Default is true
+       not {                           % If EncryptMetadata is false
+         <ff ff ff ff> concatstrings
+       } if
+     } {
+       pop
+     } ifelse
+     md5_trunk
+
+     % Step 7.  Executed as part of step 6
+     % Step 8.
      50 { md5_trunk } repeat
-  } if
+  } {
+     pop pop md5_trunk                 % Remove Encrypt dict
+  } ifelse

   % Step 7 - Done in md5_trunk.
 } bind def
@@ -362,29 +380,46 @@
     PDFfile exch resolveopdict .decpdfrun
     dup dup dup 5 2 roll
        % stack: object object key object object
-    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
+    {  % Use loop to provide an exitable context.
+      xcheck exch type /dicttype eq and % Check if executable dictionary
+      not {                            % If object is not ...
+        pop pop                                % ignore object
+        exit                           % Exit 'loop' context
+      } if                             % If not possible stream
+       % PDF 1.5 encryption (R == 4) has some extra features.  If this
+       % is not PDF 1.5 encryption (R < 4) then we need to decrypt the
+       % stream
       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
+       exit                            % Exit 'loop' context
+      } if
+       % Check if we have encrypted streams.  R == 4 (PDF 1.5) allows for
+       % selection of encryption on streams and strings.  Check for StmF
+       % == Identity
+      dup /StmF knownoget              % Get StmF (if present)
+      not { /Identity } if             % If StmF not present default =
Identity
+      /Identity eq                     % Check if StmF == Identity
+      { pop pop pop                    % Identity --> no encryption
+       exit                            % Exit 'loop' context
+      } if
+       % PDF 1.5 has a separate flag for encrypting meta data
+      /EncryptMetadata knownoget       % Get EncryptMetadata (if present)
+      not { true } if                  % If not present default = true
+      not                              % Check if false
+      {                                % if false we need to check the
stream type
+       1 index /Type knownoget         % Get stream type (if ppresent)
+       not { /Unknown } if             % If type not present use fake name
+       /Metadata eq                    % Check if the type is Metadata
+        { pop pop                      % Type == Metadata --> no encryption
+         exit                          % Exit 'loop' context
+        } if
+      } if
+       % If we get here then we need to decrypt the stream.
+      /StreamKey exch put              % Insert StreamKey into dictionary
+      exit                             % Exit 'loop' context, never loop
+    } loop                             % End of loop exitable context
   } {                                  % Else file is not encrypted
     PDFfile resolveopdict .pdfrun
   } ifelse                             % Ifelse encrypted
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.